Skip to contentSkip to conversation

crypto: dh - input validation fixes

PATCH In review Eric Biggers 3 participants 10 messages Nov 6, 2017 – Nov 10, 2017

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

v2 cover crypto: dh - input validation fixes

This series fixes several corner cases in the Diffie-Hellman key exchange implementations:

1. With the software DH implementation, using a large buffer for 'g' caused a double free.
2. With CONFIG_DEBUG_SG=y and the software DH implementation, setting 'p' to 0 caused a BUG_ON().
3. With the QAT DH implementation, setting 'key' or 'g' larger than 'p' caused a buffer underflow.

Note that in kernels configured with CONFIG_KEY_DH_OPERATIONS=y, these bugs are reachable by unprivileged users via KEYCTL_DH_COMPUTE.

Patches 4 and 5 are cleanup only.

Eric Biggers (5):
crypto: dh - Fix double free of ctx->p
crypto: dh - Don't permit 'p' to be 0
crypto: dh - Don't permit 'key' or 'g' size longer than 'p'
crypto: qat - Clean up error handling in qat_dh_set_secret()
crypto: dh - Remove pointless checks for NULL 'p' and 'g'

 crypto/dh.c                                   | 36 ++++++++++-----------------
 crypto/dh_helper.c                            | 16 ++++++++++++
 drivers/crypto/qat/qat_common/qat_asym_algs.c | 18 ++++++--------
 3 files changed, 37 insertions(+), 33 deletions(-)
Signature · 1 line
2.15.0
#1 lore raw

PATCH v2 1/5 crypto: dh - Fix double free of ctx->p

From: Eric Biggers <[email protected]>

When setting the secret with the software Diffie-Hellman implementation, if allocating 'g' failed (e.g. if it was longer than MAX_EXTERN_MPI_BITS), then 'p' was freed twice: once immediately, and once later when the crypto_kpp tfm was destroyed.

Fix it by using dh_free_ctx() (renamed to dh_clear_ctx()) in the error paths, as that correctly sets the pointers to NULL.

KASAN report:

    MPI: mpi too large (32760 bits)
    =================================
    BUG: KASAN: use-after-free in mpi_free+0x131/0x170
    Read of size 4 at addr ffff88006c7cdf90 by task reproduce_doubl/367

    CPU: 1 PID: 367 Comm: reproduce_doubl Not tainted 4.14.0-rc7-00040-g05298abde6fe #7
    Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
    Call Trace:
     dump_stack+0xb3/0x10b
     ? mpi_free+0x131/0x170
     print_address_description+0x79/0x2a0
     ? mpi_free+0x131/0x170
     kasan_report+0x236/0x340
     ? akcipher_register_instance+0x90/0x90
     __asan_report_load4_noabort+0x14/0x20
     mpi_free+0x131/0x170
     ? akcipher_register_instance+0x90/0x90
     dh_exit_tfm+0x3d/0x140
     crypto_kpp_exit_tfm+0x52/0x70
     crypto_destroy_tfm+0xb3/0x250
     __keyctl_dh_compute+0x640/0xe90
     ? kasan_slab_free+0x12f/0x180
     ? dh_data_from_key+0x240/0x240
     ? key_create_or_update+0x1ee/0xb20
     ? key_instantiate_and_link+0x440/0x440
     ? lock_contended+0xee0/0xee0
     ? kfree+0xcf/0x210
     ? SyS_add_key+0x268/0x340
     keyctl_dh_compute+0xb3/0xf1
     ? __keyctl_dh_compute+0xe90/0xe90
     ? SyS_add_key+0x26d/0x340
     ? entry_SYSCALL_64_fastpath+0x5/0xbe
     ? trace_hardirqs_on_caller+0x3f4/0x560
     SyS_keyctl+0x72/0x2c0
     entry_SYSCALL_64_fastpath+0x1f/0xbe
    RIP: 0033:0x43ccf9
    RSP: 002b:00007ffeeec96158 EFLAGS: 00000246 ORIG_RAX: 00000000000000fa
    RAX: ffffffffffffffda RBX: 000000000248b9b9 RCX: 000000000043ccf9
    RDX: 00007ffeeec96170 RSI: 00007ffeeec96160 RDI: 0000000000000017
    RBP: 0000000000000046 R08: 0000000000000000 R09: 0248b9b9143dc936
    R10: 0000000000001000 R11: 0000000000000246 R12: 0000000000000000
    R13: 0000000000409670 R14: 0000000000409700 R15: 0000000000000000

    Allocated by task 367:
     save_stack_trace+0x16/0x20
     kasan_kmalloc+0xeb/0x180
     kmem_cache_alloc_trace+0x114/0x300
     mpi_alloc+0x4b/0x230
     mpi_read_raw_data+0xbe/0x360
     dh_set_secret+0x1dc/0x460
     __keyctl_dh_compute+0x623/0xe90
     keyctl_dh_compute+0xb3/0xf1
     SyS_keyctl+0x72/0x2c0
     entry_SYSCALL_64_fastpath+0x1f/0xbe

    Freed by task 367:
     save_stack_trace+0x16/0x20
     kasan_slab_free+0xab/0x180
     kfree+0xb5/0x210
     mpi_free+0xcb/0x170
     dh_set_secret+0x2d7/0x460
     __keyctl_dh_compute+0x623/0xe90
     keyctl_dh_compute+0xb3/0xf1
     SyS_keyctl+0x72/0x2c0
     entry_SYSCALL_64_fastpath+0x1f/0xbe
Fixes 802c7f1c84e4 ("crypto: dh - Add DH software implementation")
Cc <[email protected]> # v4.8+
---
 crypto/dh.c | 33 +++++++++++++--------------------
 1 file changed, 13 insertions(+), 20 deletions(-)
crypto/dh.c +13 -20
index b1032a5c1bfa..aadaf36fb56f 100644
@@ -21,19 +21,12 @@ struct dh_ctx {
 	MPI xa;
 };
 
-static inline void dh_clear_params(struct dh_ctx *ctx)
+static void dh_clear_ctx(struct dh_ctx *ctx)
 {
 	mpi_free(ctx->p);
 	mpi_free(ctx->g);
-	ctx->p = NULL;
-	ctx->g = NULL;
-}
-
-static void dh_free_ctx(struct dh_ctx *ctx)
-{
-	dh_clear_params(ctx);
 	mpi_free(ctx->xa);
-	ctx->xa = NULL;
+	memset(ctx, 0, sizeof(*ctx));
 }
 
 /*
@@ -71,10 +64,8 @@ static int dh_set_params(struct dh_ctx *ctx, struct dh *params)
 		return -EINVAL;
 
 	ctx->g = mpi_read_raw_data(params->g, params->g_size);
-	if (!ctx->g) {
-		mpi_free(ctx->p);
+	if (!ctx->g)
 		return -EINVAL;
-	}
 
 	return 0;
 }
@@ -86,21 +77,23 @@ static int dh_set_secret(struct crypto_kpp *tfm, const void *buf,
 	struct dh params;
 
 	/* Free the old MPI key if any */
-	dh_free_ctx(ctx);
+	dh_clear_ctx(ctx);
 
 	if (crypto_dh_decode_key(buf, len, &params) < 0)
-		return -EINVAL;
+		goto err_clear_ctx;
 
 	if (dh_set_params(ctx, &params) < 0)
-		return -EINVAL;
+		goto err_clear_ctx;
 
 	ctx->xa = mpi_read_raw_data(params.key, params.key_size);
-	if (!ctx->xa) {
-		dh_clear_params(ctx);
-		return -EINVAL;
-	}
+	if (!ctx->xa)
+		goto err_clear_ctx;
 
 	return 0;
+
+err_clear_ctx:
+	dh_clear_ctx(ctx);
+	return -EINVAL;
 }
 
 static int dh_compute_value(struct kpp_request *req)
@@ -158,7 +151,7 @@ static void dh_exit_tfm(struct crypto_kpp *tfm)
 {
 	struct dh_ctx *ctx = dh_get_ctx(tfm);
 
-	dh_free_ctx(ctx);
+	dh_clear_ctx(ctx);
 }
 
 static struct kpp_alg dh = {
Signature · 1 line
2.15.0
Reviewed-by on v2 1/5
#2 lore raw

Re: [PATCH v2 1/5] crypto: dh - Fix double free of ctx->p

Quoted 78 lines · Eric Biggers

From: Eric Biggers <[email protected]>

When setting the secret with the software Diffie-Hellman implementation, if allocating 'g' failed (e.g. if it was longer than MAX_EXTERN_MPI_BITS), then 'p' was freed twice: once immediately, and once later when the crypto_kpp tfm was destroyed.

Fix it by using dh_free_ctx() (renamed to dh_clear_ctx()) in the error paths, as that correctly sets the pointers to NULL.

KASAN report:

     MPI: mpi too large (32760 bits)
     =================================
     BUG: KASAN: use-after-free in mpi_free+0x131/0x170
     Read of size 4 at addr ffff88006c7cdf90 by task reproduce_doubl/367

     CPU: 1 PID: 367 Comm: reproduce_doubl Not tainted 4.14.0-rc7-00040-g05298abde6fe #7
     Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
     Call Trace:
      dump_stack+0xb3/0x10b
      ? mpi_free+0x131/0x170
      print_address_description+0x79/0x2a0
      ? mpi_free+0x131/0x170
      kasan_report+0x236/0x340
      ? akcipher_register_instance+0x90/0x90
      __asan_report_load4_noabort+0x14/0x20
      mpi_free+0x131/0x170
      ? akcipher_register_instance+0x90/0x90
      dh_exit_tfm+0x3d/0x140
      crypto_kpp_exit_tfm+0x52/0x70
      crypto_destroy_tfm+0xb3/0x250
      __keyctl_dh_compute+0x640/0xe90
      ? kasan_slab_free+0x12f/0x180
      ? dh_data_from_key+0x240/0x240
      ? key_create_or_update+0x1ee/0xb20
      ? key_instantiate_and_link+0x440/0x440
      ? lock_contended+0xee0/0xee0
      ? kfree+0xcf/0x210
      ? SyS_add_key+0x268/0x340
      keyctl_dh_compute+0xb3/0xf1
      ? __keyctl_dh_compute+0xe90/0xe90
      ? SyS_add_key+0x26d/0x340
      ? entry_SYSCALL_64_fastpath+0x5/0xbe
      ? trace_hardirqs_on_caller+0x3f4/0x560
      SyS_keyctl+0x72/0x2c0
      entry_SYSCALL_64_fastpath+0x1f/0xbe
     RIP: 0033:0x43ccf9
     RSP: 002b:00007ffeeec96158 EFLAGS: 00000246 ORIG_RAX: 00000000000000fa
     RAX: ffffffffffffffda RBX: 000000000248b9b9 RCX: 000000000043ccf9
     RDX: 00007ffeeec96170 RSI: 00007ffeeec96160 RDI: 0000000000000017
     RBP: 0000000000000046 R08: 0000000000000000 R09: 0248b9b9143dc936
     R10: 0000000000001000 R11: 0000000000000246 R12: 0000000000000000
     R13: 0000000000409670 R14: 0000000000409700 R15: 0000000000000000

     Allocated by task 367:
      save_stack_trace+0x16/0x20
      kasan_kmalloc+0xeb/0x180
      kmem_cache_alloc_trace+0x114/0x300
      mpi_alloc+0x4b/0x230
      mpi_read_raw_data+0xbe/0x360
      dh_set_secret+0x1dc/0x460
      __keyctl_dh_compute+0x623/0xe90
      keyctl_dh_compute+0xb3/0xf1
      SyS_keyctl+0x72/0x2c0
      entry_SYSCALL_64_fastpath+0x1f/0xbe

     Freed by task 367:
      save_stack_trace+0x16/0x20
      kasan_slab_free+0xab/0x180
      kfree+0xb5/0x210
      mpi_free+0xcb/0x170
      dh_set_secret+0x2d7/0x460
      __keyctl_dh_compute+0x623/0xe90
      keyctl_dh_compute+0xb3/0xf1
      SyS_keyctl+0x72/0x2c0
      entry_SYSCALL_64_fastpath+0x1f/0xbe
Quoted 3 lines
Fixes 802c7f1c84e4 ("crypto: dh - Add DH software implementation")
Cc <[email protected]> # v4.8+
Quoted 83 lines
---
  crypto/dh.c | 33 +++++++++++++--------------------
  1 file changed, 13 insertions(+), 20 deletions(-)
crypto/dh.c +13 -20
index b1032a5c1bfa..aadaf36fb56f 100644
@@ -21,19 +21,12 @@ struct dh_ctx {
  	MPI xa;
  };
 
-static inline void dh_clear_params(struct dh_ctx *ctx)
+static void dh_clear_ctx(struct dh_ctx *ctx)
  {
  	mpi_free(ctx->p);
  	mpi_free(ctx->g);
-	ctx->p = NULL;
-	ctx->g = NULL;
-}
-
-static void dh_free_ctx(struct dh_ctx *ctx)
-{
-	dh_clear_params(ctx);
  	mpi_free(ctx->xa);
-	ctx->xa = NULL;
+	memset(ctx, 0, sizeof(*ctx));
  }
 
  /*
@@ -71,10 +64,8 @@ static int dh_set_params(struct dh_ctx *ctx, struct dh *params)
  		return -EINVAL;
 
  	ctx->g = mpi_read_raw_data(params->g, params->g_size);
-	if (!ctx->g) {
-		mpi_free(ctx->p);
+	if (!ctx->g)
  		return -EINVAL;
-	}
 
  	return 0;
  }
@@ -86,21 +77,23 @@ static int dh_set_secret(struct crypto_kpp *tfm, const void *buf,
  	struct dh params;
 
  	/* Free the old MPI key if any */
-	dh_free_ctx(ctx);
+	dh_clear_ctx(ctx);
 
  	if (crypto_dh_decode_key(buf, len, &params) < 0)
-		return -EINVAL;
+		goto err_clear_ctx;
 
  	if (dh_set_params(ctx, &params) < 0)
-		return -EINVAL;
+		goto err_clear_ctx;
 
  	ctx->xa = mpi_read_raw_data(params.key, params.key_size);
-	if (!ctx->xa) {
-		dh_clear_params(ctx);
-		return -EINVAL;
-	}
+	if (!ctx->xa)
+		goto err_clear_ctx;
 
  	return 0;
+
+err_clear_ctx:
+	dh_clear_ctx(ctx);
+	return -EINVAL;
  }
 
  static int dh_compute_value(struct kpp_request *req)
@@ -158,7 +151,7 @@ static void dh_exit_tfm(struct crypto_kpp *tfm)
  {
  	struct dh_ctx *ctx = dh_get_ctx(tfm);
 
-	dh_free_ctx(ctx);
+	dh_clear_ctx(ctx);
  }
 
  static struct kpp_alg dh = {
#3 lore raw

PATCH v2 2/5 crypto: dh - Don't permit 'p' to be 0

In reply to Eric Biggers

From: Eric Biggers <[email protected]>

If 'p' is 0 for the software Diffie-Hellman implementation, then dh_max_size() returns 0. In the case of KEYCTL_DH_COMPUTE, this causes ZERO_SIZE_PTR to be passed to sg_init_one(), which with CONFIG_DEBUG_SG=y triggers the 'BUG_ON(!virt_addr_valid(buf));' in sg_set_buf().

Fix this by making crypto_dh_decode_key() reject 0 for 'p'. p=0 makes no sense for any DH implementation because 'p' is supposed to be a prime number. Moreover, 'mod 0' is not mathematically defined.

Bug report:

    kernel BUG at ./include/linux/scatterlist.h:140!
    invalid opcode: 0000 [#1] SMP KASAN
    CPU: 0 PID: 27112 Comm: syz-executor2 Not tainted 4.14.0-rc7-00010-gf5dbb5d0ce32-dirty #7
    Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.3-20171021_125229-anatol 04/01/2014
    task: ffff88006caac0c0 task.stack: ffff88006c7c8000
    RIP: 0010:sg_set_buf include/linux/scatterlist.h:140 [inline]
    RIP: 0010:sg_init_one+0x1b3/0x240 lib/scatterlist.c:156
    RSP: 0018:ffff88006c7cfb08 EFLAGS: 00010216
    RAX: 0000000000010000 RBX: ffff88006c7cfe30 RCX: 00000000000064ee
    RDX: ffffffff81cf64c3 RSI: ffffc90000d72000 RDI: ffffffff92e937e0
    RBP: ffff88006c7cfb30 R08: ffffed000d8f9fab R09: ffff88006c7cfd30
    R10: 0000000000000005 R11: ffffed000d8f9faa R12: ffff88006c7cfd30
    R13: 0000000000000000 R14: 0000000000000010 R15: ffff88006c7cfc50
    FS:  00007fce190fa700(0000) GS:ffff88003ea00000(0000) knlGS:0000000000000000
    CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
    CR2: 00007fffc6b33db8 CR3: 000000003cf64000 CR4: 00000000000006f0
    Call Trace:
     __keyctl_dh_compute+0xa95/0x19b0 security/keys/dh.c:360
     keyctl_dh_compute+0xac/0x100 security/keys/dh.c:434
     SYSC_keyctl security/keys/keyctl.c:1745 [inline]
     SyS_keyctl+0x72/0x2c0 security/keys/keyctl.c:1641
     entry_SYSCALL_64_fastpath+0x1f/0xbe
    RIP: 0033:0x4585c9
    RSP: 002b:00007fce190f9bd8 EFLAGS: 00000216 ORIG_RAX: 00000000000000fa
    RAX: ffffffffffffffda RBX: 0000000000738020 RCX: 00000000004585c9
    RDX: 000000002000d000 RSI: 0000000020000ff4 RDI: 0000000000000017
    RBP: 0000000000000046 R08: 0000000020008000 R09: 0000000000000000
    R10: 0000000000000000 R11: 0000000000000216 R12: 00007fff6e610cde
    R13: 00007fff6e610cdf R14: 00007fce190fa700 R15: 0000000000000000
    Code: 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 33 5b 45 89 6c 24 14 41 5c 41 5d 41 5e 41 5f 5d c3 e8 fd 8f 68 ff <0f> 0b e8 f6 8f 68 ff 0f 0b e8 ef 8f 68 ff 0f 0b e8 e8 8f 68 ff 20
    RIP: sg_set_buf include/linux/scatterlist.h:140 [inline] RSP: ffff88006c7cfb08
    RIP: sg_init_one+0x1b3/0x240 lib/scatterlist.c:156 RSP: ffff88006c7cfb08
Fixes 802c7f1c84e4 ("crypto: dh - Add DH software implementation")
Cc <[email protected]> # v4.8+
---
 crypto/dh_helper.c | 8 ++++++++
 1 file changed, 8 insertions(+)
crypto/dh_helper.c +8 -0
index 8ba8a3f82620..708ae20d2d3c 100644
@@ -90,6 +90,14 @@ int crypto_dh_decode_key(const char *buf, unsigned int len, struct dh *params)
 	params->p = (void *)(ptr + params->key_size);
 	params->g = (void *)(ptr + params->key_size + params->p_size);
 
+	/*
+	 * Don't permit 'p' to be 0.  It's not a prime number, and it's subject
+	 * to corner cases such as 'mod 0' being undefined or
+	 * crypto_kpp_maxsize() returning 0.
+	 */
+	if (memchr_inv(params->p, 0, params->p_size) = NULL)
+		return -EINVAL;
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(crypto_dh_decode_key);
Signature · 1 line
2.15.0
#4 lore raw

PATCH v2 3/5 crypto: dh - Don't permit 'key' or 'g' size longer than 'p'

In reply to Eric Biggers

From: Eric Biggers <[email protected]>

The "qat-dh" DH implementation assumes that 'key' and 'g' can be copied into a buffer with size 'p_size'. However it was never checked that that was actually the case, which most likely allowed users to cause a buffer underflow via KEYCTL_DH_COMPUTE.

Fix this by updating crypto_dh_decode_key() to verify this precondition for all DH implementations.

Fixes c9839143ebbf ("crypto: qat - Add DH support")
Cc <[email protected]> # v4.8+
---
 crypto/dh_helper.c | 8 ++++++++
 1 file changed, 8 insertions(+)
crypto/dh_helper.c +8 -0
index 708ae20d2d3c..7f00c771fe8d 100644
@@ -83,6 +83,14 @@ int crypto_dh_decode_key(const char *buf, unsigned int len, struct dh *params)
 	if (secret.len != crypto_dh_key_len(params))
 		return -EINVAL;
 
+	/*
+	 * Don't permit the buffer for 'key' or 'g' to be larger than 'p', since
+	 * some drivers assume otherwise.
+	 */
+	if (params->key_size > params->p_size ||
+	    params->g_size > params->p_size)
+		return -EINVAL;
+
 	/* Don't allocate memory. Set pointers to data within
 	 * the given buffer
 	 */
Signature · 1 line
2.15.0
Reviewed-by on v2 3/5
#5 lore raw

Re: [PATCH v2 3/5] crypto: dh - Don't permit 'key' or 'g' size longer than 'p'

Quoted 7 lines · Eric Biggers

From: Eric Biggers <[email protected]>

The "qat-dh" DH implementation assumes that 'key' and 'g' can be copied into a buffer with size 'p_size'. However it was never checked that that was actually the case, which most likely allowed users to cause a buffer underflow via KEYCTL_DH_COMPUTE.

Quoted 5 lines

Fix this by updating crypto_dh_decode_key() to verify this precondition for all DH implementations.

Fixes c9839143ebbf ("crypto: qat - Add DH support")
Cc <[email protected]> # v4.8+
Quoted 25 lines
---
  crypto/dh_helper.c | 8 ++++++++
  1 file changed, 8 insertions(+)
crypto/dh_helper.c +8 -0
index 708ae20d2d3c..7f00c771fe8d 100644
@@ -83,6 +83,14 @@ int crypto_dh_decode_key(const char *buf, unsigned int len, struct dh *params)
  	if (secret.len != crypto_dh_key_len(params))
  		return -EINVAL;
 
+	/*
+	 * Don't permit the buffer for 'key' or 'g' to be larger than 'p', since
+	 * some drivers assume otherwise.
+	 */
+	if (params->key_size > params->p_size ||
+	    params->g_size > params->p_size)
+		return -EINVAL;
+
  	/* Don't allocate memory. Set pointers to data within
  	 * the given buffer
  	 */
#6 lore raw

PATCH v2 4/5 crypto: qat - Clean up error handling in qat_dh_set_secret()

In reply to Eric Biggers

From: Eric Biggers <[email protected]>

Update the error handling in qat_dh_set_secret() to mirror dh_set_secret(). The new version is less error-prone because freeing memory and setting the pointers to NULL is now only done in one place.

---
 drivers/crypto/qat/qat_common/qat_asym_algs.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)
drivers/crypto/qat/qat_common/qat_asym_algs.c +8 -7
index 6f5dd68449c6..7655fdb499de 100644
@@ -462,11 +462,8 @@ static int qat_dh_set_params(struct qat_dh_ctx *ctx, struct dh *params)
 	}
 
 	ctx->g = dma_zalloc_coherent(dev, ctx->p_size, &ctx->dma_g, GFP_KERNEL);
-	if (!ctx->g) {
-		dma_free_coherent(dev, ctx->p_size, ctx->p, ctx->dma_p);
-		ctx->p = NULL;
+	if (!ctx->g)
 		return -ENOMEM;
-	}
 	memcpy(ctx->g + (ctx->p_size - params->g_size), params->g,
 	       params->g_size);
 
@@ -507,18 +504,22 @@ static int qat_dh_set_secret(struct crypto_kpp *tfm, const void *buf,
 
 	ret = qat_dh_set_params(ctx, &params);
 	if (ret < 0)
-		return ret;
+		goto err_clear_ctx;
 
 	ctx->xa = dma_zalloc_coherent(dev, ctx->p_size, &ctx->dma_xa,
 				      GFP_KERNEL);
 	if (!ctx->xa) {
-		qat_dh_clear_ctx(dev, ctx);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto err_clear_ctx;
 	}
 	memcpy(ctx->xa + (ctx->p_size - params.key_size), params.key,
 	       params.key_size);
 
 	return 0;
+
+err_clear_ctx:
+	qat_dh_clear_ctx(dev, ctx);
+	return ret;
 }
 
 static unsigned int qat_dh_max_size(struct crypto_kpp *tfm)
Signature · 1 line
2.15.0
#7 lore raw

PATCH v2 5/5 crypto: dh - Remove pointless checks for NULL 'p' and 'g'

In reply to Eric Biggers

From: Eric Biggers <[email protected]>

Neither 'p' nor 'g' can be NULL, as they were unpacked using crypto_dh_decode_key(). And it makes no sense for them to be optional. So remove the NULL checks that were copy-and-pasted into both modules.

---
 crypto/dh.c                                   | 3 ---
 drivers/crypto/qat/qat_common/qat_asym_algs.c | 3 ---
 2 files changed, 6 deletions(-)
crypto/dh.c +0 -3
index aadaf36fb56f..5659fe7f446d 100644
@@ -53,9 +53,6 @@ static int dh_check_params_length(unsigned int p_len)
 
 static int dh_set_params(struct dh_ctx *ctx, struct dh *params)
 {
-	if (unlikely(!params->p || !params->g))
-		return -EINVAL;
-
 	if (dh_check_params_length(params->p_size << 3))
 		return -EINVAL;
 
drivers/crypto/qat/qat_common/qat_asym_algs.c +0 -3
index 7655fdb499de..13c52d6bf630 100644
@@ -443,9 +443,6 @@ static int qat_dh_set_params(struct qat_dh_ctx *ctx, struct dh *params)
 	struct qat_crypto_instance *inst = ctx->inst;
 	struct device *dev = &GET_DEV(inst->accel_dev);
 
-	if (unlikely(!params->p || !params->g))
-		return -EINVAL;
-
 	if (qat_dh_check_params_length(params->p_size << 3))
 		return -EINVAL;
 
Signature · 1 line
2.15.0
Reviewed-by on v2 5/5
#8 lore raw

Re: [PATCH v2 5/5] crypto: dh - Remove pointless checks for NULL 'p' and 'g'

Quoted 6 lines · Eric Biggers

From: Eric Biggers <[email protected]>

Neither 'p' nor 'g' can be NULL, as they were unpacked using crypto_dh_decode_key(). And it makes no sense for them to be optional. So remove the NULL checks that were copy-and-pasted into both modules.

Quoted 35 lines
---
  crypto/dh.c                                   | 3 ---
  drivers/crypto/qat/qat_common/qat_asym_algs.c | 3 ---
  2 files changed, 6 deletions(-)
crypto/dh.c +0 -3
index aadaf36fb56f..5659fe7f446d 100644
@@ -53,9 +53,6 @@ static int dh_check_params_length(unsigned int p_len)
 
  static int dh_set_params(struct dh_ctx *ctx, struct dh *params)
  {
-	if (unlikely(!params->p || !params->g))
-		return -EINVAL;
-
  	if (dh_check_params_length(params->p_size << 3))
  		return -EINVAL;
 
drivers/crypto/qat/qat_common/qat_asym_algs.c +0 -3
index 7655fdb499de..13c52d6bf630 100644
@@ -443,9 +443,6 @@ static int qat_dh_set_params(struct qat_dh_ctx *ctx, struct dh *params)
  	struct qat_crypto_instance *inst = ctx->inst;
  	struct device *dev = &GET_DEV(inst->accel_dev);
 
-	if (unlikely(!params->p || !params->g))
-		return -EINVAL;
-
  	if (qat_dh_check_params_length(params->p_size << 3))
  		return -EINVAL;
 
maintainer
#9 lore raw
In reply to Eric Biggers
Quoted 13 lines · Eric Biggers

This series fixes several corner cases in the Diffie-Hellman key exchange implementations:

1. With the software DH implementation, using a large buffer for 'g' caused a double free.
2. With CONFIG_DEBUG_SG=y and the software DH implementation, setting 'p' to 0 caused a BUG_ON().
3. With the QAT DH implementation, setting 'key' or 'g' larger than 'p' caused a buffer underflow.

Note that in kernels configured with CONFIG_KEY_DH_OPERATIONS=y, these bugs are reachable by unprivileged users via KEYCTL_DH_COMPUTE.

Quoted 8 lines

Patches 4 and 5 are cleanup only.

Eric Biggers (5):
crypto: dh - Fix double free of ctx->p
crypto: dh - Don't permit 'p' to be 0
crypto: dh - Don't permit 'key' or 'g' size longer than 'p'
crypto: qat - Clean up error handling in qat_dh_set_secret()
crypto: dh - Remove pointless checks for NULL 'p' and 'g'

All applied. Thanks.

Signature · 3 lines
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt