diff mbox series

[10/12] crypto: qat - use memzero_explicit() for algs

Message ID 20220506082327.21605-11-giovanni.cabiddu@intel.com (mailing list archive)
State Superseded
Delegated to: Herbert Xu
Headers show
Series crypto: qat - re-enable algorithms | expand

Commit Message

Cabiddu, Giovanni May 6, 2022, 8:23 a.m. UTC
Use memzero_explicit(), instead of a memset(.., 0, ..) in the
implementation of the algorithms, for buffers containing sensitive
information to ensure they are wiped out before free.

Cc: stable@vger.kernel.org
Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Reviewed-by: Adam Guerin <adam.guerin@intel.com>
Reviewed-by: Wojciech Ziemba <wojciech.ziemba@intel.com>
---
 drivers/crypto/qat/qat_common/qat_algs.c      | 20 +++++++++----------
 drivers/crypto/qat/qat_common/qat_asym_algs.c | 20 +++++++++----------
 2 files changed, 20 insertions(+), 20 deletions(-)

Comments

Greg KH May 6, 2022, 9:22 a.m. UTC | #1
On Fri, May 06, 2022 at 09:23:25AM +0100, Giovanni Cabiddu wrote:
> Use memzero_explicit(), instead of a memset(.., 0, ..) in the
> implementation of the algorithms, for buffers containing sensitive
> information to ensure they are wiped out before free.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
> Reviewed-by: Adam Guerin <adam.guerin@intel.com>
> Reviewed-by: Wojciech Ziemba <wojciech.ziemba@intel.com>
> ---
>  drivers/crypto/qat/qat_common/qat_algs.c      | 20 +++++++++----------
>  drivers/crypto/qat/qat_common/qat_asym_algs.c | 20 +++++++++----------
>  2 files changed, 20 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
> index 873533dc43a7..c42df18e02b2 100644
> --- a/drivers/crypto/qat/qat_common/qat_algs.c
> +++ b/drivers/crypto/qat/qat_common/qat_algs.c
> @@ -637,12 +637,12 @@ static int qat_alg_aead_newkey(struct crypto_aead *tfm, const u8 *key,
>  	return 0;
>  
>  out_free_all:
> -	memset(ctx->dec_cd, 0, sizeof(struct qat_alg_cd));
> +	memzero_explicit(ctx->dec_cd, sizeof(struct qat_alg_cd));

This is for structure fields, why does memset() not work properly here?
The compiler should always call this, it doesn't know what
dma_free_coherent() does.  You are referencing this pointer after the
memset() call so all should be working as intended here.

Because of this, I don't see why this change is needed.  Do you have
reports of compilers not calling memset() for all of this properly?

thanks,

greg k-h
Cabiddu, Giovanni May 6, 2022, 9:54 a.m. UTC | #2
On Fri, May 06, 2022 at 11:22:39AM +0200, Greg KH wrote:
> On Fri, May 06, 2022 at 09:23:25AM +0100, Giovanni Cabiddu wrote:
> > Use memzero_explicit(), instead of a memset(.., 0, ..) in the
> > implementation of the algorithms, for buffers containing sensitive
> > information to ensure they are wiped out before free.
> > 
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
> > Reviewed-by: Adam Guerin <adam.guerin@intel.com>
> > Reviewed-by: Wojciech Ziemba <wojciech.ziemba@intel.com>
> > ---
> >  drivers/crypto/qat/qat_common/qat_algs.c      | 20 +++++++++----------
> >  drivers/crypto/qat/qat_common/qat_asym_algs.c | 20 +++++++++----------
> >  2 files changed, 20 insertions(+), 20 deletions(-)
> > 
> > diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
> > index 873533dc43a7..c42df18e02b2 100644
> > --- a/drivers/crypto/qat/qat_common/qat_algs.c
> > +++ b/drivers/crypto/qat/qat_common/qat_algs.c
> > @@ -637,12 +637,12 @@ static int qat_alg_aead_newkey(struct crypto_aead *tfm, const u8 *key,
> >  	return 0;
> >  
> >  out_free_all:
> > -	memset(ctx->dec_cd, 0, sizeof(struct qat_alg_cd));
> > +	memzero_explicit(ctx->dec_cd, sizeof(struct qat_alg_cd));
> 
> This is for structure fields, why does memset() not work properly here?
> The compiler should always call this, it doesn't know what
> dma_free_coherent() does.  You are referencing this pointer after the
> memset() call so all should be working as intended here.
> 
> Because of this, I don't see why this change is needed.  Do you have
> reports of compilers not calling memset() for all of this properly?
Apologies, I had a wrong assumption.
Based on a comment in the memzero_explicit() documentation I assumed it
should be always used to zero sensitive data.

     * memzero_explicit - Fill a region of memory (e.g. sensitive
     *			  keying data) with 0s.

I'm going to drop this patch.

Thanks,
Greg KH May 6, 2022, 2:38 p.m. UTC | #3
On Fri, May 06, 2022 at 10:54:07AM +0100, Giovanni Cabiddu wrote:
> On Fri, May 06, 2022 at 11:22:39AM +0200, Greg KH wrote:
> > On Fri, May 06, 2022 at 09:23:25AM +0100, Giovanni Cabiddu wrote:
> > > Use memzero_explicit(), instead of a memset(.., 0, ..) in the
> > > implementation of the algorithms, for buffers containing sensitive
> > > information to ensure they are wiped out before free.
> > > 
> > > Cc: stable@vger.kernel.org
> > > Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
> > > Reviewed-by: Adam Guerin <adam.guerin@intel.com>
> > > Reviewed-by: Wojciech Ziemba <wojciech.ziemba@intel.com>
> > > ---
> > >  drivers/crypto/qat/qat_common/qat_algs.c      | 20 +++++++++----------
> > >  drivers/crypto/qat/qat_common/qat_asym_algs.c | 20 +++++++++----------
> > >  2 files changed, 20 insertions(+), 20 deletions(-)
> > > 
> > > diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
> > > index 873533dc43a7..c42df18e02b2 100644
> > > --- a/drivers/crypto/qat/qat_common/qat_algs.c
> > > +++ b/drivers/crypto/qat/qat_common/qat_algs.c
> > > @@ -637,12 +637,12 @@ static int qat_alg_aead_newkey(struct crypto_aead *tfm, const u8 *key,
> > >  	return 0;
> > >  
> > >  out_free_all:
> > > -	memset(ctx->dec_cd, 0, sizeof(struct qat_alg_cd));
> > > +	memzero_explicit(ctx->dec_cd, sizeof(struct qat_alg_cd));
> > 
> > This is for structure fields, why does memset() not work properly here?
> > The compiler should always call this, it doesn't know what
> > dma_free_coherent() does.  You are referencing this pointer after the
> > memset() call so all should be working as intended here.
> > 
> > Because of this, I don't see why this change is needed.  Do you have
> > reports of compilers not calling memset() for all of this properly?
> Apologies, I had a wrong assumption.
> Based on a comment in the memzero_explicit() documentation I assumed it
> should be always used to zero sensitive data.
> 
>      * memzero_explicit - Fill a region of memory (e.g. sensitive
>      *			  keying data) with 0s.

Yes, that's what it is for, when the compiler thinks it is "smarter than
you" for stack variables.

It's great for functions like this:
	int foo(...)
	{
		struct key secret_key;

		do something and set secret_key...

		/* All done, clean up and return */
		memset(&secret_key, 0, sizeof(secret_key));
		return 0;
	}

For that, some compilers now go "hey, they just want to set this to 0
and then never touch it again, that is pointless, let's not call
memset() at all!".

But when you call:
	memset(foo->key, 0, sizeof(key));
	do_something_with_foo(foo);

the compiler can NOT go and ignore the call to memset() as it does not
know what do_something_with_foo() does.  Or at least it better not.

Try out this with a small example and look at the asm output for proof.

You aren't the first to be confused about this, I see this happening at
least once a month with a patch to change code like you did.  Don't know
why it keeps coming up, is this a checkpatch() recommentation?

thanks,

greg k-h
Cabiddu, Giovanni May 9, 2022, 8:50 a.m. UTC | #4
On Fri, May 06, 2022 at 04:38:15PM +0200, Greg KH wrote:
> On Fri, May 06, 2022 at 10:54:07AM +0100, Giovanni Cabiddu wrote:
> > On Fri, May 06, 2022 at 11:22:39AM +0200, Greg KH wrote:
> > > On Fri, May 06, 2022 at 09:23:25AM +0100, Giovanni Cabiddu wrote:
> > > > Use memzero_explicit(), instead of a memset(.., 0, ..) in the
> > > > implementation of the algorithms, for buffers containing sensitive
> > > > information to ensure they are wiped out before free.
> > > > 
> > > > Cc: stable@vger.kernel.org
> > > > Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
> > > > Reviewed-by: Adam Guerin <adam.guerin@intel.com>
> > > > Reviewed-by: Wojciech Ziemba <wojciech.ziemba@intel.com>
> > > > ---
> > > >  drivers/crypto/qat/qat_common/qat_algs.c      | 20 +++++++++----------
> > > >  drivers/crypto/qat/qat_common/qat_asym_algs.c | 20 +++++++++----------
> > > >  2 files changed, 20 insertions(+), 20 deletions(-)
> > > > 
> > > > diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
> > > > index 873533dc43a7..c42df18e02b2 100644
> > > > --- a/drivers/crypto/qat/qat_common/qat_algs.c
> > > > +++ b/drivers/crypto/qat/qat_common/qat_algs.c
> > > > @@ -637,12 +637,12 @@ static int qat_alg_aead_newkey(struct crypto_aead *tfm, const u8 *key,
> > > >  	return 0;
> > > >  
> > > >  out_free_all:
> > > > -	memset(ctx->dec_cd, 0, sizeof(struct qat_alg_cd));
> > > > +	memzero_explicit(ctx->dec_cd, sizeof(struct qat_alg_cd));
> > > 
> > > This is for structure fields, why does memset() not work properly here?
> > > The compiler should always call this, it doesn't know what
> > > dma_free_coherent() does.  You are referencing this pointer after the
> > > memset() call so all should be working as intended here.
> > > 
> > > Because of this, I don't see why this change is needed.  Do you have
> > > reports of compilers not calling memset() for all of this properly?
> > Apologies, I had a wrong assumption.
> > Based on a comment in the memzero_explicit() documentation I assumed it
> > should be always used to zero sensitive data.
> > 
> >      * memzero_explicit - Fill a region of memory (e.g. sensitive
> >      *			  keying data) with 0s.
> 
> Yes, that's what it is for, when the compiler thinks it is "smarter than
> you" for stack variables.
> 
> It's great for functions like this:
> 	int foo(...)
> 	{
> 		struct key secret_key;
> 
> 		do something and set secret_key...
> 
> 		/* All done, clean up and return */
> 		memset(&secret_key, 0, sizeof(secret_key));
> 		return 0;
> 	}
> 
> For that, some compilers now go "hey, they just want to set this to 0
> and then never touch it again, that is pointless, let's not call
> memset() at all!".
> 
> But when you call:
> 	memset(foo->key, 0, sizeof(key));
> 	do_something_with_foo(foo);
> 
> the compiler can NOT go and ignore the call to memset() as it does not
> know what do_something_with_foo() does.  Or at least it better not.
> 
> Try out this with a small example and look at the asm output for proof.
Thanks for the explanation. It is clear now.

> 
> You aren't the first to be confused about this, I see this happening at
> least once a month with a patch to change code like you did.  Don't know
> why it keeps coming up, is this a checkpatch() recommentation?
It is not a checkpatch recommendation.
I got that assumption looking at kfree_sensitive() which contains a call
to memzero_explicit(). This was introduced in 2020 by
8982ae527fbe ("mm/slab: use memzero_explicit() in kzfree()" when the
function was still called kzfree().
I assume now that the call to memzero_explicit() in kfree_sensitive() is
also redundant, unless I'm missing something.

Regards,
Greg KH May 9, 2022, 9:42 a.m. UTC | #5
On Mon, May 09, 2022 at 09:50:58AM +0100, Giovanni Cabiddu wrote:
> On Fri, May 06, 2022 at 04:38:15PM +0200, Greg KH wrote:
> > On Fri, May 06, 2022 at 10:54:07AM +0100, Giovanni Cabiddu wrote:
> > > On Fri, May 06, 2022 at 11:22:39AM +0200, Greg KH wrote:
> > > > On Fri, May 06, 2022 at 09:23:25AM +0100, Giovanni Cabiddu wrote:
> > > > > Use memzero_explicit(), instead of a memset(.., 0, ..) in the
> > > > > implementation of the algorithms, for buffers containing sensitive
> > > > > information to ensure they are wiped out before free.
> > > > > 
> > > > > Cc: stable@vger.kernel.org
> > > > > Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
> > > > > Reviewed-by: Adam Guerin <adam.guerin@intel.com>
> > > > > Reviewed-by: Wojciech Ziemba <wojciech.ziemba@intel.com>
> > > > > ---
> > > > >  drivers/crypto/qat/qat_common/qat_algs.c      | 20 +++++++++----------
> > > > >  drivers/crypto/qat/qat_common/qat_asym_algs.c | 20 +++++++++----------
> > > > >  2 files changed, 20 insertions(+), 20 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
> > > > > index 873533dc43a7..c42df18e02b2 100644
> > > > > --- a/drivers/crypto/qat/qat_common/qat_algs.c
> > > > > +++ b/drivers/crypto/qat/qat_common/qat_algs.c
> > > > > @@ -637,12 +637,12 @@ static int qat_alg_aead_newkey(struct crypto_aead *tfm, const u8 *key,
> > > > >  	return 0;
> > > > >  
> > > > >  out_free_all:
> > > > > -	memset(ctx->dec_cd, 0, sizeof(struct qat_alg_cd));
> > > > > +	memzero_explicit(ctx->dec_cd, sizeof(struct qat_alg_cd));
> > > > 
> > > > This is for structure fields, why does memset() not work properly here?
> > > > The compiler should always call this, it doesn't know what
> > > > dma_free_coherent() does.  You are referencing this pointer after the
> > > > memset() call so all should be working as intended here.
> > > > 
> > > > Because of this, I don't see why this change is needed.  Do you have
> > > > reports of compilers not calling memset() for all of this properly?
> > > Apologies, I had a wrong assumption.
> > > Based on a comment in the memzero_explicit() documentation I assumed it
> > > should be always used to zero sensitive data.
> > > 
> > >      * memzero_explicit - Fill a region of memory (e.g. sensitive
> > >      *			  keying data) with 0s.
> > 
> > Yes, that's what it is for, when the compiler thinks it is "smarter than
> > you" for stack variables.
> > 
> > It's great for functions like this:
> > 	int foo(...)
> > 	{
> > 		struct key secret_key;
> > 
> > 		do something and set secret_key...
> > 
> > 		/* All done, clean up and return */
> > 		memset(&secret_key, 0, sizeof(secret_key));
> > 		return 0;
> > 	}
> > 
> > For that, some compilers now go "hey, they just want to set this to 0
> > and then never touch it again, that is pointless, let's not call
> > memset() at all!".
> > 
> > But when you call:
> > 	memset(foo->key, 0, sizeof(key));
> > 	do_something_with_foo(foo);
> > 
> > the compiler can NOT go and ignore the call to memset() as it does not
> > know what do_something_with_foo() does.  Or at least it better not.
> > 
> > Try out this with a small example and look at the asm output for proof.
> Thanks for the explanation. It is clear now.
> 
> > 
> > You aren't the first to be confused about this, I see this happening at
> > least once a month with a patch to change code like you did.  Don't know
> > why it keeps coming up, is this a checkpatch() recommentation?
> It is not a checkpatch recommendation.
> I got that assumption looking at kfree_sensitive() which contains a call
> to memzero_explicit(). This was introduced in 2020 by
> 8982ae527fbe ("mm/slab: use memzero_explicit() in kzfree()" when the
> function was still called kzfree().
> I assume now that the call to memzero_explicit() in kfree_sensitive() is
> also redundant, unless I'm missing something.

Maybe it is, it's hard to tell without running some build tests on
different compilers.  Try it and see!

thanks,

greg k-h
diff mbox series

Patch

diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
index 873533dc43a7..c42df18e02b2 100644
--- a/drivers/crypto/qat/qat_common/qat_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_algs.c
@@ -637,12 +637,12 @@  static int qat_alg_aead_newkey(struct crypto_aead *tfm, const u8 *key,
 	return 0;
 
 out_free_all:
-	memset(ctx->dec_cd, 0, sizeof(struct qat_alg_cd));
+	memzero_explicit(ctx->dec_cd, sizeof(struct qat_alg_cd));
 	dma_free_coherent(dev, sizeof(struct qat_alg_cd),
 			  ctx->dec_cd, ctx->dec_cd_paddr);
 	ctx->dec_cd = NULL;
 out_free_enc:
-	memset(ctx->enc_cd, 0, sizeof(struct qat_alg_cd));
+	memzero_explicit(ctx->enc_cd, sizeof(struct qat_alg_cd));
 	dma_free_coherent(dev, sizeof(struct qat_alg_cd),
 			  ctx->enc_cd, ctx->enc_cd_paddr);
 	ctx->enc_cd = NULL;
@@ -1092,12 +1092,12 @@  static int qat_alg_skcipher_newkey(struct qat_alg_skcipher_ctx *ctx,
 	return 0;
 
 out_free_all:
-	memset(ctx->dec_cd, 0, sizeof(*ctx->dec_cd));
+	memzero_explicit(ctx->dec_cd, sizeof(*ctx->dec_cd));
 	dma_free_coherent(dev, sizeof(*ctx->dec_cd),
 			  ctx->dec_cd, ctx->dec_cd_paddr);
 	ctx->dec_cd = NULL;
 out_free_enc:
-	memset(ctx->enc_cd, 0, sizeof(*ctx->enc_cd));
+	memzero_explicit(ctx->enc_cd, sizeof(*ctx->enc_cd));
 	dma_free_coherent(dev, sizeof(*ctx->enc_cd),
 			  ctx->enc_cd, ctx->enc_cd_paddr);
 	ctx->enc_cd = NULL;
@@ -1359,12 +1359,12 @@  static void qat_alg_aead_exit(struct crypto_aead *tfm)
 
 	dev = &GET_DEV(inst->accel_dev);
 	if (ctx->enc_cd) {
-		memset(ctx->enc_cd, 0, sizeof(struct qat_alg_cd));
+		memzero_explicit(ctx->enc_cd, sizeof(struct qat_alg_cd));
 		dma_free_coherent(dev, sizeof(struct qat_alg_cd),
 				  ctx->enc_cd, ctx->enc_cd_paddr);
 	}
 	if (ctx->dec_cd) {
-		memset(ctx->dec_cd, 0, sizeof(struct qat_alg_cd));
+		memzero_explicit(ctx->dec_cd, sizeof(struct qat_alg_cd));
 		dma_free_coherent(dev, sizeof(struct qat_alg_cd),
 				  ctx->dec_cd, ctx->dec_cd_paddr);
 	}
@@ -1412,15 +1412,15 @@  static void qat_alg_skcipher_exit_tfm(struct crypto_skcipher *tfm)
 
 	dev = &GET_DEV(inst->accel_dev);
 	if (ctx->enc_cd) {
-		memset(ctx->enc_cd, 0,
-		       sizeof(struct icp_qat_hw_cipher_algo_blk));
+		memzero_explicit(ctx->enc_cd,
+				 sizeof(struct icp_qat_hw_cipher_algo_blk));
 		dma_free_coherent(dev,
 				  sizeof(struct icp_qat_hw_cipher_algo_blk),
 				  ctx->enc_cd, ctx->enc_cd_paddr);
 	}
 	if (ctx->dec_cd) {
-		memset(ctx->dec_cd, 0,
-		       sizeof(struct icp_qat_hw_cipher_algo_blk));
+		memzero_explicit(ctx->dec_cd,
+				 sizeof(struct icp_qat_hw_cipher_algo_blk));
 		dma_free_coherent(dev,
 				  sizeof(struct icp_qat_hw_cipher_algo_blk),
 				  ctx->dec_cd, ctx->dec_cd_paddr);
diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c
index b3badc5bd224..86c7d07435c8 100644
--- a/drivers/crypto/qat/qat_common/qat_asym_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_asym_algs.c
@@ -1087,19 +1087,19 @@  static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key)
 	return;
 
 free_dq:
-	memset(ctx->dq, '\0', half_key_sz);
+	memzero_explicit(ctx->dq, half_key_sz);
 	dma_free_coherent(dev, half_key_sz, ctx->dq, ctx->dma_dq);
 	ctx->dq = NULL;
 free_dp:
-	memset(ctx->dp, '\0', half_key_sz);
+	memzero_explicit(ctx->dp, half_key_sz);
 	dma_free_coherent(dev, half_key_sz, ctx->dp, ctx->dma_dp);
 	ctx->dp = NULL;
 free_q:
-	memset(ctx->q, '\0', half_key_sz);
+	memzero_explicit(ctx->q, half_key_sz);
 	dma_free_coherent(dev, half_key_sz, ctx->q, ctx->dma_q);
 	ctx->q = NULL;
 free_p:
-	memset(ctx->p, '\0', half_key_sz);
+	memzero_explicit(ctx->p, half_key_sz);
 	dma_free_coherent(dev, half_key_sz, ctx->p, ctx->dma_p);
 	ctx->p = NULL;
 err:
@@ -1116,27 +1116,27 @@  static void qat_rsa_clear_ctx(struct device *dev, struct qat_rsa_ctx *ctx)
 	if (ctx->e)
 		dma_free_coherent(dev, ctx->key_sz, ctx->e, ctx->dma_e);
 	if (ctx->d) {
-		memset(ctx->d, '\0', ctx->key_sz);
+		memzero_explicit(ctx->d, ctx->key_sz);
 		dma_free_coherent(dev, ctx->key_sz, ctx->d, ctx->dma_d);
 	}
 	if (ctx->p) {
-		memset(ctx->p, '\0', half_key_sz);
+		memzero_explicit(ctx->p, half_key_sz);
 		dma_free_coherent(dev, half_key_sz, ctx->p, ctx->dma_p);
 	}
 	if (ctx->q) {
-		memset(ctx->q, '\0', half_key_sz);
+		memzero_explicit(ctx->q, half_key_sz);
 		dma_free_coherent(dev, half_key_sz, ctx->q, ctx->dma_q);
 	}
 	if (ctx->dp) {
-		memset(ctx->dp, '\0', half_key_sz);
+		memzero_explicit(ctx->dp, half_key_sz);
 		dma_free_coherent(dev, half_key_sz, ctx->dp, ctx->dma_dp);
 	}
 	if (ctx->dq) {
-		memset(ctx->dq, '\0', half_key_sz);
+		memzero_explicit(ctx->dq, half_key_sz);
 		dma_free_coherent(dev, half_key_sz, ctx->dq, ctx->dma_dq);
 	}
 	if (ctx->qinv) {
-		memset(ctx->qinv, '\0', half_key_sz);
+		memzero_explicit(ctx->qinv, half_key_sz);
 		dma_free_coherent(dev, half_key_sz, ctx->qinv, ctx->dma_qinv);
 	}