diff mbox

[v2,3/4] crypto: inside-secure - only update the result buffer when provided

Message ID 20171128154236.19192-4-antoine.tenart@free-electrons.com (mailing list archive)
State Changes Requested
Delegated to: Herbert Xu
Headers show

Commit Message

Antoine Tenart Nov. 28, 2017, 3:42 p.m. UTC
The patch fixes the ahash support by only updating the result buffer
when provided. Otherwise the driver could crash with NULL pointer
exceptions, because the ahash caller isn't required to supply a result
buffer on all calls.

Fixes: 1b44c5a60c13 ("crypto: inside-secure - add SafeXcel EIP197 crypto engine driver")
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
 drivers/crypto/inside-secure/safexcel_hash.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

Comments

Kamil Konieczny Nov. 30, 2017, 9:19 a.m. UTC | #1
Hi Antoine,

On 28.11.2017 16:42, Antoine Tenart wrote:
> The patch fixes the ahash support by only updating the result buffer
> when provided. Otherwise the driver could crash with NULL pointer
> exceptions, because the ahash caller isn't required to supply a result
> buffer on all calls.

Can you point to bug crush report ?

> Fixes: 1b44c5a60c13 ("crypto: inside-secure - add SafeXcel EIP197 crypto engine driver")
> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> ---
>  drivers/crypto/inside-secure/safexcel_hash.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c
> index 6135c9f5742c..424f4c5d4d25 100644
> --- a/drivers/crypto/inside-secure/safexcel_hash.c
> +++ b/drivers/crypto/inside-secure/safexcel_hash.c
> @@ -150,7 +150,12 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin
>  
>  	if (sreq->finish)
>  		result_sz = crypto_ahash_digestsize(ahash);
> -	memcpy(sreq->state, areq->result, result_sz);
> +
> +	/* The called isn't required to supply a result buffer. Updated it only
> +	 * when provided.
> +	 */
> +	if (areq->result)
> +		memcpy(sreq->state, areq->result, result_sz);
>  
>  	dma_unmap_sg(priv->dev, areq->src,
>  		     sg_nents_for_len(areq->src, areq->nbytes), DMA_TO_DEVICE);
> 

can the driver get request for final/finup/digest with null req->result ?
If yes (?), such checks can be done before any hardware processing, saving time,
for example:

int hash_final(struct ahash_request *areq)
{
	if (!areq->result)
		return -EINVAL;
	/* normal processing here */
}
Antoine Tenart Nov. 30, 2017, 9:29 a.m. UTC | #2
Hi Kamil,

On Thu, Nov 30, 2017 at 10:19:26AM +0100, Kamil Konieczny wrote:
> On 28.11.2017 16:42, Antoine Tenart wrote:
> > The patch fixes the ahash support by only updating the result buffer
> > when provided. Otherwise the driver could crash with NULL pointer
> > exceptions, because the ahash caller isn't required to supply a result
> > buffer on all calls.
> 
> Can you point to bug crush report ?

Do you want the crash dump? (It'll only be a "normal" NULL pointer
dereference).

> > Fixes: 1b44c5a60c13 ("crypto: inside-secure - add SafeXcel EIP197 crypto engine driver")
> > Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> > ---
> >  drivers/crypto/inside-secure/safexcel_hash.c | 7 ++++++-
> >  1 file changed, 6 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c
> > index 6135c9f5742c..424f4c5d4d25 100644
> > --- a/drivers/crypto/inside-secure/safexcel_hash.c
> > +++ b/drivers/crypto/inside-secure/safexcel_hash.c
> > @@ -150,7 +150,12 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin
> >  
> >  	if (sreq->finish)
> >  		result_sz = crypto_ahash_digestsize(ahash);
> > -	memcpy(sreq->state, areq->result, result_sz);
> > +
> > +	/* The called isn't required to supply a result buffer. Updated it only
> > +	 * when provided.
> > +	 */
> > +	if (areq->result)
> > +		memcpy(sreq->state, areq->result, result_sz);
> >  
> >  	dma_unmap_sg(priv->dev, areq->src,
> >  		     sg_nents_for_len(areq->src, areq->nbytes), DMA_TO_DEVICE);
> > 
> 
> can the driver get request for final/finup/digest with null req->result ?

I don't think that can happen. But having an update called without
req->result provided is a valid call (though it's not well documented).

Thanks,
Antoine
Kamil Konieczny Nov. 30, 2017, 11:52 a.m. UTC | #3
Hi Antoine,

On 30.11.2017 10:29, Antoine Tenart wrote:
> Hi Kamil,
> 
> On Thu, Nov 30, 2017 at 10:19:26AM +0100, Kamil Konieczny wrote:
>> On 28.11.2017 16:42, Antoine Tenart wrote:
>>> The patch fixes the ahash support by only updating the result buffer
>>> when provided. Otherwise the driver could crash with NULL pointer
>>> exceptions, because the ahash caller isn't required to supply a result
>>> buffer on all calls.
>>
>> Can you point to bug crush report ?
> 
> Do you want the crash dump? (It'll only be a "normal" NULL pointer
> dereference).

Ah I see, in this case not.

>>> Fixes: 1b44c5a60c13 ("crypto: inside-secure - add SafeXcel EIP197 crypto engine driver")
>>> Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
>>> ---
>>>  drivers/crypto/inside-secure/safexcel_hash.c | 7 ++++++-
>>>  1 file changed, 6 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c
>>> index 6135c9f5742c..424f4c5d4d25 100644
>>> --- a/drivers/crypto/inside-secure/safexcel_hash.c
>>> +++ b/drivers/crypto/inside-secure/safexcel_hash.c
>>> @@ -150,7 +150,12 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin
>>>  
>>>  	if (sreq->finish)
>>>  		result_sz = crypto_ahash_digestsize(ahash);
>>> -	memcpy(sreq->state, areq->result, result_sz);
>> [...]
>> can the driver get request for final/finup/digest with null req->result ?
> 
> I don't think that can happen. But having an update called without
> req->result provided is a valid call (though it's not well documented).

so maybe:

 	if (sreq->finish) {
  		result_sz = crypto_ahash_digestsize(ahash);
		memcpy(sreq->state, areq->result, result_sz);
	}
Antoine Tenart Nov. 30, 2017, 12:41 p.m. UTC | #4
On Thu, Nov 30, 2017 at 12:52:42PM +0100, Kamil Konieczny wrote:
> On 30.11.2017 10:29, Antoine Tenart wrote:
> > On Thu, Nov 30, 2017 at 10:19:26AM +0100, Kamil Konieczny wrote:
> >> can the driver get request for final/finup/digest with null req->result ?
> > 
> > I don't think that can happen. But having an update called without
> > req->result provided is a valid call (though it's not well documented).
> 
> so maybe:
> 
>  	if (sreq->finish) {
>   		result_sz = crypto_ahash_digestsize(ahash);
> 		memcpy(sreq->state, areq->result, result_sz);
> 	}

No, if we do this we'll lose the ability to export the current state.

Thanks,
Antoine
Kamil Konieczny Nov. 30, 2017, 2:10 p.m. UTC | #5
On 30.11.2017 13:41, Antoine Tenart wrote:
> On Thu, Nov 30, 2017 at 12:52:42PM +0100, Kamil Konieczny wrote:
>> On 30.11.2017 10:29, Antoine Tenart wrote:
>>> On Thu, Nov 30, 2017 at 10:19:26AM +0100, Kamil Konieczny wrote:

>>>> can the driver get request for final/finup/digest with null req->result ?
>>>
>>> I don't think that can happen. But having an update called without
>>> req->result provided is a valid call (though it's not well documented).

Yes, this field may be unset until finup/final.
One more to watch out is that in final, you can have areq->nsize != 0 so
you should not use  areq->nsize nor areq->src

>> so maybe:
>>
>>  	if (sreq->finish) {
>>   		result_sz = crypto_ahash_digestsize(ahash);
>> 		memcpy(sreq->state, areq->result, result_sz);
>> 	}
> 
> No, if we do this we'll lose the ability to export the current state.

So maybe save it into request context:

	result_sz = crypto_ahash_digestsize(ahash);
	ctx = ahash_request_ctx(areq);

  	if (sreq->finish)
 		memcpy(sreq->state, areq->result, result_sz);
	else
		memcpy(sreq->state, ctx->state, result_sz);
Antoine Tenart Nov. 30, 2017, 2:30 p.m. UTC | #6
Hi Kamil,

On Thu, Nov 30, 2017 at 03:10:28PM +0100, Kamil Konieczny wrote:
> On 30.11.2017 13:41, Antoine Tenart wrote:
> > 
> > No, if we do this we'll lose the ability to export the current state.
> 
> So maybe save it into request context:
> 
> 	result_sz = crypto_ahash_digestsize(ahash);
> 	ctx = ahash_request_ctx(areq);
> 
>   	if (sreq->finish)
>  		memcpy(sreq->state, areq->result, result_sz);
> 	else
> 		memcpy(sreq->state, ctx->state, result_sz);

Storing the digest into a driver own buffer could improve the export
ability in some *very rare* cases. If so I would suggest not to deal
with the kind of test you proposed, but to have your own buffer used
each time.

Anyway, this has nothing to do with the fix I'm proposing here, as it
would change the driver's logic, and would solve a complete different
(rare) issue.

The proposal here is to have a simple fix (which is similar to what can
be found in some other drivers), that can easily be backported to avoid
NULL pointer dereferences in older versions of the kernel.

Thanks,
Antoine
Herbert Xu Dec. 1, 2017, 12:31 a.m. UTC | #7
On Thu, Nov 30, 2017 at 10:19:26AM +0100, Kamil Konieczny wrote:
>
> can the driver get request for final/finup/digest with null req->result ?
> If yes (?), such checks can be done before any hardware processing, saving time,
> for example:

This should not be possible through any user-space facing API.

If a kernel API user did this then they're just shooting themselves
in the foot.

So unless there is a valida call path that leads to this then I
would say that there is nothing to fix.

Thanks,
Antoine Tenart Dec. 1, 2017, 8:11 a.m. UTC | #8
Hi Herbert,

On Fri, Dec 01, 2017 at 11:31:09AM +1100, Herbert Xu wrote:
> On Thu, Nov 30, 2017 at 10:19:26AM +0100, Kamil Konieczny wrote:
> >
> > can the driver get request for final/finup/digest with null req->result ?
> > If yes (?), such checks can be done before any hardware processing, saving time,
> > for example:
> 
> This should not be possible through any user-space facing API.
> 
> If a kernel API user did this then they're just shooting themselves
> in the foot.
> 
> So unless there is a valida call path that leads to this then I
> would say that there is nothing to fix.

I agree this should not be the case.

But:
- Other drivers are doing this check (grep "if (!req->result)" or
  "if (req->result)" to see some of them).
- I see at least one commit fixing the exact same issue I'm facing here,
  393897c5156a415533ff85aa381458840417b032:

    crypto: ccp - Check for caller result area before using it

    For a hash operation, the caller doesn't have to supply a result
    area on every call so don't use it / update it if it hasn't
    been supplied.

I'm not entirely sure what was the code path that leads to this, I'll
reproduce the issue and try to understand what is going on (I clearly
recall having this crash though).

The crypto API does not enforce this somehow, and this should probably
be fixed. That might break some users. But it was seen as a valid use
for some, so we should probably fix this in previous versions of the
driver anyway.

Thanks!
Antoine
Kamil Konieczny Dec. 1, 2017, 10:18 a.m. UTC | #9
Hi All,

On 01.12.2017 09:11, Antoine Tenart wrote:
> Hi Herbert,
> 
> On Fri, Dec 01, 2017 at 11:31:09AM +1100, Herbert Xu wrote:
>> On Thu, Nov 30, 2017 at 10:19:26AM +0100, Kamil Konieczny wrote:
>>>
>>> can the driver get request for final/finup/digest with null req->result ?
>>> If yes (?), such checks can be done before any hardware processing, saving time,
>>> for example:
>>
>> This should not be possible through any user-space facing API.
>>
>> If a kernel API user did this then they're just shooting themselves
>> in the foot.
>>
>> So unless there is a valida call path that leads to this then I
>> would say that there is nothing to fix.
> 
> I agree this should not be the case.
> 
> But:
> - Other drivers are doing this check (grep "if (!req->result)" or
>   "if (req->result)" to see some of them).
> - I see at least one commit fixing the exact same issue I'm facing here,
>   393897c5156a415533ff85aa381458840417b032:
> 
>     crypto: ccp - Check for caller result area before using it
> 
>     For a hash operation, the caller doesn't have to supply a result
>     area on every call so don't use it / update it if it hasn't
>     been supplied.

Herbert, is it possible for every init/update that areq->result can be NULL,
and only for final/update/digit user set it to actual memory ?
testmgr.c can check if hash update writes into areq->result and if yes, 
then test fails ?

As I understand this, when crypto api user allocates ahash_request, 
crypto allocates memory for itself _plus_ for driver's context. This allocated
ahash_request is "handle" for all subsequent updates/export/import, 
and for last final/finup, so I do not need to copy hash state into areq->result,
but keep it whole time in context, in your code in sreq:

struct safexcel_ahash_req *sreq = ahash_request_ctx(areq);

so here sreq is async hash request context.

Do you set last_req true for digest/finup/final ? If yes,
then you need to copy result only when it is true,

	if (sreq->last_req) {
		result_sz = crypto_ahash_digestsize(ahash);
		memcpy(sreq->state, areq->result, result_sz);
	}

I do not read all your code though, so I can be wrong here.
 
> I'm not entirely sure what was the code path that leads to this, I'll
> reproduce the issue and try to understand what is going on (I clearly
> recall having this crash though).
> 
> The crypto API does not enforce this somehow, and this should probably
> be fixed. That might break some users. But it was seen as a valid use
> for some, so we should probably fix this in previous versions of the
> driver anyway.
Antoine Tenart Dec. 1, 2017, 10:24 a.m. UTC | #10
Hi Kamil,

On Fri, Dec 01, 2017 at 11:18:30AM +0100, Kamil Konieczny wrote:
> On 01.12.2017 09:11, Antoine Tenart wrote:
> > - Other drivers are doing this check (grep "if (!req->result)" or
> >   "if (req->result)" to see some of them).
> > - I see at least one commit fixing the exact same issue I'm facing here,
> >   393897c5156a415533ff85aa381458840417b032:
> > 
> >     crypto: ccp - Check for caller result area before using it
> > 
> >     For a hash operation, the caller doesn't have to supply a result
> >     area on every call so don't use it / update it if it hasn't
> >     been supplied.
> 
> Do you set last_req true for digest/finup/final ? If yes,
> then you need to copy result only when it is true,
> 
> 	if (sreq->last_req) {
> 		result_sz = crypto_ahash_digestsize(ahash);
> 		memcpy(sreq->state, areq->result, result_sz);
> 	}

Yes the last_req flag is set for the last request, so when
digest/finup/final are called. But no we can't copy the result into the
state based on this as an user might want to perform multiple updates,
then export the context, to import it again before sending more updates.

Antoine
Herbert Xu Dec. 1, 2017, 10:35 a.m. UTC | #11
On Fri, Dec 01, 2017 at 09:11:57AM +0100, Antoine Tenart wrote:
>
> I agree this should not be the case.
> 
> But:
> - Other drivers are doing this check (grep "if (!req->result)" or
>   "if (req->result)" to see some of them).
> - I see at least one commit fixing the exact same issue I'm facing here,
>   393897c5156a415533ff85aa381458840417b032:
> 
>     crypto: ccp - Check for caller result area before using it
> 
>     For a hash operation, the caller doesn't have to supply a result
>     area on every call so don't use it / update it if it hasn't
>     been supplied.
> 
> I'm not entirely sure what was the code path that leads to this, I'll
> reproduce the issue and try to understand what is going on (I clearly
> recall having this crash though).

That's different.  In that case an unconditional copy is made
regardless of whether the operation is final or update.  That's
why a check is required.

If the operation is finup/final/digest then req->result must be
set and you don't need to check it.

Cheers,
Herbert Xu Dec. 1, 2017, 10:36 a.m. UTC | #12
On Fri, Dec 01, 2017 at 11:18:30AM +0100, Kamil Konieczny wrote:
>
> Herbert, is it possible for every init/update that areq->result can be NULL,
> and only for final/update/digit user set it to actual memory ?
> testmgr.c can check if hash update writes into areq->result and if yes, 
> then test fails ?

Yes we should modify testmgr to check that.

Thanks,
Kamil Konieczny Dec. 1, 2017, 10:43 a.m. UTC | #13
Hi Antoine,

On 01.12.2017 11:24, Antoine Tenart wrote:
> Hi Kamil,
> 
> On Fri, Dec 01, 2017 at 11:18:30AM +0100, Kamil Konieczny wrote:
>> On 01.12.2017 09:11, Antoine Tenart wrote:
>>> - Other drivers are doing this check (grep "if (!req->result)" or
>>>   "if (req->result)" to see some of them).
>>> - I see at least one commit fixing the exact same issue I'm facing here,
>>>   393897c5156a415533ff85aa381458840417b032:
>>>
>>>     crypto: ccp - Check for caller result area before using it
>>>
>>>     For a hash operation, the caller doesn't have to supply a result
>>>     area on every call so don't use it / update it if it hasn't
>>>     been supplied.
>>
>> Do you set last_req true for digest/finup/final ? If yes,
>> then you need to copy result only when it is true,
>>
>> 	if (sreq->last_req) {
>> 		result_sz = crypto_ahash_digestsize(ahash);
>> 		memcpy(sreq->state, areq->result, result_sz);
>> 	}
> 
> Yes the last_req flag is set for the last request, so when
> digest/finup/final are called. But no we can't copy the result into the
> state based on this as an user might want to perform multiple updates,
> then export the context, to import it again before sending more updates.

IMHO set them to false in hash update and init, set finish false and last_req true
for hash final, and set both true for hash finup and digest.

As Herbert tells in https://www.spinics.net/lists/linux-crypto/msg28658.html
you should support scenario export + update/finup, so basically export is reading
state but it do not halt your hash driver.
Antoine Tenart Dec. 1, 2017, 10:52 a.m. UTC | #14
Hi Herbert,

On Fri, Dec 01, 2017 at 09:35:52PM +1100, Herbert Xu wrote:
> On Fri, Dec 01, 2017 at 09:11:57AM +0100, Antoine Tenart wrote:
> >
> > I agree this should not be the case.
> > 
> > But:
> > - Other drivers are doing this check (grep "if (!req->result)" or
> >   "if (req->result)" to see some of them).
> > - I see at least one commit fixing the exact same issue I'm facing here,
> >   393897c5156a415533ff85aa381458840417b032:
> > 
> >     crypto: ccp - Check for caller result area before using it
> > 
> >     For a hash operation, the caller doesn't have to supply a result
> >     area on every call so don't use it / update it if it hasn't
> >     been supplied.
> > 
> > I'm not entirely sure what was the code path that leads to this, I'll
> > reproduce the issue and try to understand what is going on (I clearly
> > recall having this crash though).
> 
> That's different.  In that case an unconditional copy is made
> regardless of whether the operation is final or update.  That's
> why a check is required.
> 
> If the operation is finup/final/digest then req->result must be
> set and you don't need to check it.

Ah, I didn't understand your point then. Of course ->result should be
allocated for finup/final/digest. The function where I fix this is
called regardless of the operation that was performed, so it can be an
update() as well.

Thanks,
Antoine
Antoine Tenart Dec. 1, 2017, 10:55 a.m. UTC | #15
On Fri, Dec 01, 2017 at 11:43:18AM +0100, Kamil Konieczny wrote:
> On 01.12.2017 11:24, Antoine Tenart wrote:
> > 
> > Yes the last_req flag is set for the last request, so when
> > digest/finup/final are called. But no we can't copy the result into the
> > state based on this as an user might want to perform multiple updates,
> > then export the context, to import it again before sending more updates.
> 
> IMHO set them to false in hash update and init, set finish false and last_req true
> for hash final, and set both true for hash finup and digest.
> 
> As Herbert tells in https://www.spinics.net/lists/linux-crypto/msg28658.html
> you should support scenario export + update/finup, so basically export is reading
> state but it do not halt your hash driver.

Except if you import another state in the meantime.

Antoine
Kamil Konieczny Dec. 1, 2017, 11:24 a.m. UTC | #16
Hi Herbert,

On 01.12.2017 11:36, Herbert Xu wrote:
> On Fri, Dec 01, 2017 at 11:18:30AM +0100, Kamil Konieczny wrote:
>>
>> Herbert, is it possible for every init/update that areq->result can be NULL,
>> and only for final/update/digit user set it to actual memory ?
>> testmgr.c can check if hash update writes into areq->result and if yes, 
>> then test fails ?
> 
> Yes we should modify testmgr to check that.

I can write patch for it. Should it WARN_ON or treat it as error ?
diff mbox

Patch

diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c
index 6135c9f5742c..424f4c5d4d25 100644
--- a/drivers/crypto/inside-secure/safexcel_hash.c
+++ b/drivers/crypto/inside-secure/safexcel_hash.c
@@ -150,7 +150,12 @@  static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin
 
 	if (sreq->finish)
 		result_sz = crypto_ahash_digestsize(ahash);
-	memcpy(sreq->state, areq->result, result_sz);
+
+	/* The called isn't required to supply a result buffer. Updated it only
+	 * when provided.
+	 */
+	if (areq->result)
+		memcpy(sreq->state, areq->result, result_sz);
 
 	dma_unmap_sg(priv->dev, areq->src,
 		     sg_nents_for_len(areq->src, areq->nbytes), DMA_TO_DEVICE);