diff mbox

crypto: afalg: fix a NULL pointer dereference

Message ID 1509949271-36280-1-git-send-email-longpeng2@huawei.com (mailing list archive)
State New, archived
Headers show

Commit Message

Longpeng(Mike) Nov. 6, 2017, 6:21 a.m. UTC
Test-crypto-hash calls qcrypto_hash_bytesv/digest/base64 with
errp=NULL, this will cause a NULL poniter deference if afalg_driver
doesn't support requested algos:
    ret = qcrypto_hash_afalg_driver.hash_bytesv(alg, iov, niov,
                                                result, resultlen,
                                                errp);
    if (ret == 0) {
        return ret;
    }

    error_free(*errp);  // <--- here

So we must check 'errp & *errp' before dereference.

Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
---
 crypto/hash.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

Comments

Gonglei (Arei) Nov. 6, 2017, 10:21 a.m. UTC | #1
> -----Original Message-----
> From: longpeng
> Sent: Monday, November 06, 2017 2:21 PM
> To: berrange@redhat.com; pbonzini@redhat.com; Gonglei (Arei)
> Cc: longpeng; qemu-devel@nongnu.org
> Subject: [PATCH] crypto: afalg: fix a NULL pointer dereference
> 
> Test-crypto-hash calls qcrypto_hash_bytesv/digest/base64 with
> errp=NULL, this will cause a NULL poniter deference if afalg_driver
> doesn't support requested algos:
>     ret = qcrypto_hash_afalg_driver.hash_bytesv(alg, iov, niov,
>                                                 result, resultlen,
>                                                 errp);
>     if (ret == 0) {
>         return ret;
>     }
> 
>     error_free(*errp);  // <--- here
> 
> So we must check 'errp & *errp' before dereference.
> 
> Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
> ---

Reported-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Gonglei <arei.gonglei@huawei.com>

Thanks,
-Gonglei

>  crypto/hash.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/crypto/hash.c b/crypto/hash.c
> index ac59c63..c464c78 100644
> --- a/crypto/hash.c
> +++ b/crypto/hash.c
> @@ -60,7 +60,9 @@ int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
>       * TODO:
>       * Maybe we should treat some afalg errors as fatal
>       */
> -    error_free(*errp);
> +    if (errp && *errp) {
> +        error_free(*errp);
> +    }
>  #endif
> 
>      return qcrypto_hash_lib_driver.hash_bytesv(alg, iov, niov,
> --
> 1.8.3.1
>
Eric Blake Nov. 6, 2017, 5 p.m. UTC | #2
On 11/06/2017 12:21 AM, Longpeng(Mike) wrote:
> Test-crypto-hash calls qcrypto_hash_bytesv/digest/base64 with
> errp=NULL, this will cause a NULL poniter deference if afalg_driver

s/poniter deference/pointer dereference/

> doesn't support requested algos:
>     ret = qcrypto_hash_afalg_driver.hash_bytesv(alg, iov, niov,
>                                                 result, resultlen,
>                                                 errp);
>     if (ret == 0) {
>         return ret;
>     }
> 
>     error_free(*errp);  // <--- here
> 
> So we must check 'errp & *errp' before dereference.

No, if we are going to blindly ignore the error from the hash_bytesv()
call, then we should pass NULL rather than errp.

> 
> Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
> ---
>  crypto/hash.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/crypto/hash.c b/crypto/hash.c
> index ac59c63..c464c78 100644
> --- a/crypto/hash.c
> +++ b/crypto/hash.c
> @@ -60,7 +60,9 @@ int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
>       * TODO:
>       * Maybe we should treat some afalg errors as fatal
>       */
> -    error_free(*errp);
> +    if (errp && *errp) {
> +        error_free(*errp);
> +    }

Any code that uses 'if (errp && *errp)' is suspicious; I think you need
a v2 that doesn't try to set errp in the first place, rather than
cleaning it up to ignore it after the fact.
Stefan Hajnoczi Nov. 6, 2017, 5:18 p.m. UTC | #3
On Mon, Nov 06, 2017 at 02:21:11PM +0800, Longpeng(Mike) wrote:
> Test-crypto-hash calls qcrypto_hash_bytesv/digest/base64 with
> errp=NULL, this will cause a NULL poniter deference if afalg_driver
> doesn't support requested algos:
>     ret = qcrypto_hash_afalg_driver.hash_bytesv(alg, iov, niov,
>                                                 result, resultlen,
>                                                 errp);
>     if (ret == 0) {
>         return ret;
>     }
> 
>     error_free(*errp);  // <--- here
> 
> So we must check 'errp & *errp' before dereference.

Only errp needs to be checked.  It's okay to invoke error_free(NULL):

  void error_free(Error *err)
  {
      if (err) {
Longpeng(Mike) Nov. 7, 2017, 1:13 a.m. UTC | #4
On 2017/11/7 1:18, Stefan Hajnoczi wrote:

> On Mon, Nov 06, 2017 at 02:21:11PM +0800, Longpeng(Mike) wrote:
>> Test-crypto-hash calls qcrypto_hash_bytesv/digest/base64 with
>> errp=NULL, this will cause a NULL poniter deference if afalg_driver
>> doesn't support requested algos:
>>     ret = qcrypto_hash_afalg_driver.hash_bytesv(alg, iov, niov,
>>                                                 result, resultlen,
>>                                                 errp);
>>     if (ret == 0) {
>>         return ret;
>>     }
>>
>>     error_free(*errp);  // <--- here
>>
>> So we must check 'errp & *errp' before dereference.
> 
> Only errp needs to be checked.  It's okay to invoke error_free(NULL):
> 
>   void error_free(Error *err)
>   {
>       if (err) {


Ah yes, thanks for your note :)

I'll pick another approach to fix this bug.
Longpeng(Mike) Nov. 7, 2017, 2:27 a.m. UTC | #5
On 2017/11/7 1:00, Eric Blake wrote:

> On 11/06/2017 12:21 AM, Longpeng(Mike) wrote:
>> Test-crypto-hash calls qcrypto_hash_bytesv/digest/base64 with
>> errp=NULL, this will cause a NULL poniter deference if afalg_driver
> 
> s/poniter deference/pointer dereference/
> 

OK.

>> doesn't support requested algos:
>>     ret = qcrypto_hash_afalg_driver.hash_bytesv(alg, iov, niov,
>>                                                 result, resultlen,
>>                                                 errp);
>>     if (ret == 0) {
>>         return ret;
>>     }
>>
>>     error_free(*errp);  // <--- here
>>
>> So we must check 'errp & *errp' before dereference.
> 
> No, if we are going to blindly ignore the error from the hash_bytesv()
> call, then we should pass NULL rather than errp.
> 

The 'errp' in this palce is convenient for debug, it can tell us the reason for
failure without stepping into afalg_driver's hash_bytesv().

>>
>> Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
>> ---
>>  crypto/hash.c | 4 +++-
>>  1 file changed, 3 insertions(+), 1 deletion(-)
>>
>> diff --git a/crypto/hash.c b/crypto/hash.c
>> index ac59c63..c464c78 100644
>> --- a/crypto/hash.c
>> +++ b/crypto/hash.c
>> @@ -60,7 +60,9 @@ int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
>>       * TODO:
>>       * Maybe we should treat some afalg errors as fatal
>>       */
>> -    error_free(*errp);
>> +    if (errp && *errp) {
>> +        error_free(*errp);
>> +    }
> 
> Any code that uses 'if (errp && *errp)' is suspicious; I think you need

I see, thanks a lot.

> a v2 that doesn't try to set errp in the first place, rather than
> cleaning it up to ignore it after the fact.
> 

I answered above.

How about the following approach?

int qcrypto_hash_bytesv(...Error **errp)
{
#ifdef CONFIG_AF_ALG
    int ret;
    Error *err2 = NULL;

    ret = qcrypto_hash_afalg_driver.hash_bytesv(alg, iov, niov,
                                                result, resultlen,
                                                &err2);
    if (ret == 0) {
        return ret;
    }

    error_free(*err2);
#endif

    return qcrypto_hash_lib_driver.hash_bytesv(alg, iov, niov,
                                               result, resultlen,
                                               errp);
}

I'll send a V2 if there's no objection, otherwise I'll pick your suggested
approach. :)
Daniel P. Berrangé Nov. 7, 2017, 9:16 a.m. UTC | #6
On Tue, Nov 07, 2017 at 10:27:10AM +0800, Longpeng (Mike) wrote:
> 
> 
> On 2017/11/7 1:00, Eric Blake wrote:
> 
> > On 11/06/2017 12:21 AM, Longpeng(Mike) wrote:
> >> Test-crypto-hash calls qcrypto_hash_bytesv/digest/base64 with
> >> errp=NULL, this will cause a NULL poniter deference if afalg_driver
> > 
> > s/poniter deference/pointer dereference/
> > 
> 
> OK.
> 
> >> doesn't support requested algos:
> >>     ret = qcrypto_hash_afalg_driver.hash_bytesv(alg, iov, niov,
> >>                                                 result, resultlen,
> >>                                                 errp);
> >>     if (ret == 0) {
> >>         return ret;
> >>     }
> >>
> >>     error_free(*errp);  // <--- here
> >>
> >> So we must check 'errp & *errp' before dereference.
> > 
> > No, if we are going to blindly ignore the error from the hash_bytesv()
> > call, then we should pass NULL rather than errp.
> > 
> 
> The 'errp' in this palce is convenient for debug, it can tell us the reason for
> failure without stepping into afalg_driver's hash_bytesv().

It doesn't do anything useful for debug, because we are just immediately
throwing away the error without printing it anywhere. Just pass NULL into
the hash_bytesv call above.

Regards,
Daniel
Longpeng(Mike) Nov. 7, 2017, 9:32 a.m. UTC | #7
On 2017/11/7 17:16, Daniel P. Berrange wrote:

> On Tue, Nov 07, 2017 at 10:27:10AM +0800, Longpeng (Mike) wrote:
>>
>>
>> On 2017/11/7 1:00, Eric Blake wrote:
>>
>>> On 11/06/2017 12:21 AM, Longpeng(Mike) wrote:
>>>> Test-crypto-hash calls qcrypto_hash_bytesv/digest/base64 with
>>>> errp=NULL, this will cause a NULL poniter deference if afalg_driver
>>>
>>> s/poniter deference/pointer dereference/
>>>
>>
>> OK.
>>
>>>> doesn't support requested algos:
>>>>     ret = qcrypto_hash_afalg_driver.hash_bytesv(alg, iov, niov,
>>>>                                                 result, resultlen,
>>>>                                                 errp);
>>>>     if (ret == 0) {
>>>>         return ret;
>>>>     }
>>>>
>>>>     error_free(*errp);  // <--- here
>>>>
>>>> So we must check 'errp & *errp' before dereference.
>>>
>>> No, if we are going to blindly ignore the error from the hash_bytesv()
>>> call, then we should pass NULL rather than errp.
>>>
>>
>> The 'errp' in this palce is convenient for debug, it can tell us the reason for
>> failure without stepping into afalg_driver's hash_bytesv().
> 
> It doesn't do anything useful for debug, because we are just immediately
> throwing away the error without printing it anywhere. Just pass NULL into
> the hash_bytesv call above.
> 

OK..

Afalg-backend cipher/hmac has the same usage, so maybe I need to correct all of
them.

> Regards,
> Daniel
diff mbox

Patch

diff --git a/crypto/hash.c b/crypto/hash.c
index ac59c63..c464c78 100644
--- a/crypto/hash.c
+++ b/crypto/hash.c
@@ -60,7 +60,9 @@  int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
      * TODO:
      * Maybe we should treat some afalg errors as fatal
      */
-    error_free(*errp);
+    if (errp && *errp) {
+        error_free(*errp);
+    }
 #endif
 
     return qcrypto_hash_lib_driver.hash_bytesv(alg, iov, niov,