All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/1] crypto: Avoid a sleepable operation when freeing a SCTP socket
@ 2023-08-02 17:09 Florent Revest
  2023-08-02 17:09 ` [RFC 1/1] crypto: Defer transforms destruction to a worker function Florent Revest
  2023-08-03  9:59 ` crypto: api - Use work queue in crypto_destroy_instance Herbert Xu
  0 siblings, 2 replies; 6+ messages in thread
From: Florent Revest @ 2023-08-02 17:09 UTC (permalink / raw)
  To: linux-crypto, linux-kernel, linux-sctp
  Cc: herbert, davem, hillf.zj, marcelo.leitner, lucien.xin, Florent Revest

Hi!

I found that the following program reliably reproduces a "BUG: sleeping function
called from invalid context" backtrace in crypto code:

#include <sys/socket.h>
#include <linux/in.h>
#include <linux/if_alg.h>

int main(void)
{
	int fd1 = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP);
	if (fd1 == -1)
		return 1;
	listen(fd1, 1);

	int fd2 = socket(AF_ALG, SOCK_SEQPACKET, 0);
	if (fd2 == -1)
		return 2;
	struct sockaddr_alg addr = {
		.salg_family = AF_ALG,
		.salg_type = "hash",
		.salg_name = "cryptd(md5-generic)",
	};
	bind(fd2, &addr, sizeof(addr));

	return 0;
}

The backtraces look like:

...
 __might_sleep+0x8f/0xe0 kernel/sched/core.c:7260
 down_write+0x78/0x180 kernel/locking/rwsem.c:1556
 crypto_drop_spawn+0x50/0x220 crypto/algapi.c:709
 shash_free_singlespawn_instance+0x19/0x30 crypto/shash.c:621
 crypto_shash_free_instance+0x35/0x40 crypto/shash.c:458
 crypto_free_instance crypto/algapi.c:68 [inline]
 crypto_destroy_instance+0x7d/0xb0 crypto/algapi.c:76
 crypto_alg_put crypto/internal.h:108 [inline]
 crypto_mod_put crypto/api.c:45 [inline]
 crypto_destroy_tfm+0x1f7/0x250 crypto/api.c:573
 crypto_free_shash include/crypto/hash.h:734 [inline]
 sctp_destruct_common net/sctp/socket.c:5003 [inline]
 sctp_v6_destruct_sock+0x40/0x50 net/sctp/socket.c:9436
 __sk_destruct+0x56/0x780 net/core/sock.c:1784
 sk_destruct net/core/sock.c:1829 [inline]
 __sk_free+0x36c/0x470 net/core/sock.c:1840
 sk_free+0x51/0x90 net/core/sock.c:1851
 sock_put include/net/sock.h:1815 [inline]
 sctp_endpoint_destroy_rcu+0xa6/0xf0 net/sctp/endpointola.c:193
 rcu_do_batch kernel/rcu/tree.c:2492 [inline]
 rcu_core+0x7cc/0x1260 kernel/rcu/tree.c:2733
 rcu_core_si+0x9/0x10 kernel/rcu/tree.c:2746
 __do_softirq+0x3dc/0x93b kernel/softirq.c:298
...

My analysis is that, when the process dies, the socket freeing is done in a RCU
callback, therefore under softirq context, therefore sleeping is disabled. As
part of freeing a SCTP socket, we free a cryptographical transform that frees a
"spawn" and this grabs a semaphore which triggers this BUG under
CONFIG_DEBUG_ATOMIC_SLEEP=y.

I believe that we could solve this problem by defering any part of this
backtrace into a worker function. Unfortunately, I have no clue about anything
SCTP nor anything crypto/ so I took a stab at defering... something. :) I marked
this as RFC to make it clear I don't hold strong opinions about what should be
defered exactly and expect this will probably change as a result of code review.

I believe that the same bug has been reported by syzbot twice in the past,
without reproducers and once with a slight twist:
- Once, upon freeing a sctp socket (the backtraces are very similar)
  https://lore.kernel.org/all/00000000000060f19905a74b6825@google.com/T/
  but as far as I can tell the conversation focused on the safety of kfree()
  rather than the semaphore protecting the spawns list (maybe I'm missing
  something here ?)
- Once, upon freeing a tipc socket:
  https://lore.kernel.org/all/000000000000c9257305c61c742c@google.com/T/
  Hillf proposed a fix but, as far as I can tell, it didn't get much attention
  and focused solely on addressing the bug for tipc sockets.
  My fix is inspired by this but further down the backtrace to make the fix work
  for both tipc and sctp (and potentially more ?) sockets freeing.

This patch should apply cleanly on v6.5-rc3.

Florent Revest (1):
  crypto: Defer transforms destruction to a worker function

 crypto/api.c           | 26 ++++++++++++++++++--------
 include/linux/crypto.h |  3 +++
 2 files changed, 21 insertions(+), 8 deletions(-)

-- 
2.41.0.585.gd2178a4bd4-goog


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC 1/1] crypto: Defer transforms destruction to a worker function
  2023-08-02 17:09 [RFC 0/1] crypto: Avoid a sleepable operation when freeing a SCTP socket Florent Revest
@ 2023-08-02 17:09 ` Florent Revest
  2023-08-03  6:56   ` kernel test robot
  2023-08-03  8:07   ` kernel test robot
  2023-08-03  9:59 ` crypto: api - Use work queue in crypto_destroy_instance Herbert Xu
  1 sibling, 2 replies; 6+ messages in thread
From: Florent Revest @ 2023-08-02 17:09 UTC (permalink / raw)
  To: linux-crypto, linux-kernel, linux-sctp
  Cc: herbert, davem, hillf.zj, marcelo.leitner, lucien.xin,
	Florent Revest, syzbot+d769eed29cc42d75e2a3,
	syzbot+610ec0671f51e838436e

Currently, crypto spawns can be freed in a softirq context (eg: from
sctp socket destruction's rcu callbacks). In that context, grabbing the
crypto_alg_sem is dangerous and makes CONFIG_DEBUG_ATOMIC_SLEEP scream.

Defer transform destruction to a worker function so they don't use that
semaphore in a softirq.

Reported-by: syzbot+d769eed29cc42d75e2a3@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=d769eed29cc42d75e2a3
Reported-by: syzbot+610ec0671f51e838436e@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=610ec0671f51e838436e
Signed-off-by: Florent Revest <revest@chromium.org>
---
 crypto/api.c           | 26 ++++++++++++++++++--------
 include/linux/crypto.h |  3 +++
 2 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/crypto/api.c b/crypto/api.c
index b9cc0c906efe..f877251954d5 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -640,6 +640,21 @@ void *crypto_alloc_tfm_node(const char *alg_name,
 }
 EXPORT_SYMBOL_GPL(crypto_alloc_tfm_node);
 
+void crypto_destroy_tfm_workfn(struct work_struct *w)
+{
+	struct crypto_alg *alg;
+	struct crypto_tfm *tfm;
+
+	tfm = container_of(w, struct crypto_tfm, free_work);
+	alg = tfm->__crt_alg;
+
+	if (!tfm->exit && alg->cra_exit)
+		alg->cra_exit(tfm);
+	crypto_exit_ops(tfm);
+	crypto_mod_put(alg);
+	kfree_sensitive(tfm->to_free);
+}
+
 /*
  *	crypto_destroy_tfm - Free crypto transform
  *	@mem: Start of tfm slab
@@ -650,20 +665,15 @@ EXPORT_SYMBOL_GPL(crypto_alloc_tfm_node);
  */
 void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm)
 {
-	struct crypto_alg *alg;
-
 	if (IS_ERR_OR_NULL(mem))
 		return;
 
 	if (!refcount_dec_and_test(&tfm->refcnt))
 		return;
-	alg = tfm->__crt_alg;
 
-	if (!tfm->exit && alg->cra_exit)
-		alg->cra_exit(tfm);
-	crypto_exit_ops(tfm);
-	crypto_mod_put(alg);
-	kfree_sensitive(mem);
+	tfm->to_free = mem;
+	INIT_WORK(&tfm->free_work, crypto_destroy_tfm_workfn);
+	queue_work(system_unbound_wq, &tfm->free_work);
 }
 EXPORT_SYMBOL_GPL(crypto_destroy_tfm);
 
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 31f6fee0c36c..34ff2e1dca2b 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -430,6 +430,9 @@ struct crypto_tfm {
 	
 	struct crypto_alg *__crt_alg;
 
+	struct work_struct free_work;
+	void *to_free;
+
 	void *__crt_ctx[] CRYPTO_MINALIGN_ATTR;
 };
 
-- 
2.41.0.585.gd2178a4bd4-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [RFC 1/1] crypto: Defer transforms destruction to a worker function
  2023-08-02 17:09 ` [RFC 1/1] crypto: Defer transforms destruction to a worker function Florent Revest
@ 2023-08-03  6:56   ` kernel test robot
  2023-08-03  8:07   ` kernel test robot
  1 sibling, 0 replies; 6+ messages in thread
From: kernel test robot @ 2023-08-03  6:56 UTC (permalink / raw)
  To: Florent Revest; +Cc: oe-kbuild-all

Hi Florent,

[This is a private test report for your RFC patch.]
kernel test robot noticed the following build warnings:

[auto build test WARNING on herbert-cryptodev-2.6/master]
[also build test WARNING on herbert-crypto-2.6/master linus/master v6.5-rc4 next-20230802]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Florent-Revest/crypto-Defer-transforms-destruction-to-a-worker-function/20230803-011553
base:   https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
patch link:    https://lore.kernel.org/r/20230802170923.1151605-2-revest%40chromium.org
patch subject: [RFC 1/1] crypto: Defer transforms destruction to a worker function
config: x86_64-defconfig (https://download.01.org/0day-ci/archive/20230803/202308031414.WPeu5kKk-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce: (https://download.01.org/0day-ci/archive/20230803/202308031414.WPeu5kKk-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202308031414.WPeu5kKk-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> crypto/api.c:643:6: warning: no previous prototype for 'crypto_destroy_tfm_workfn' [-Wmissing-prototypes]
     643 | void crypto_destroy_tfm_workfn(struct work_struct *w)
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~


vim +/crypto_destroy_tfm_workfn +643 crypto/api.c

   642	
 > 643	void crypto_destroy_tfm_workfn(struct work_struct *w)
   644	{
   645		struct crypto_alg *alg;
   646		struct crypto_tfm *tfm;
   647	
   648		tfm = container_of(w, struct crypto_tfm, free_work);
   649		alg = tfm->__crt_alg;
   650	
   651		if (!tfm->exit && alg->cra_exit)
   652			alg->cra_exit(tfm);
   653		crypto_exit_ops(tfm);
   654		crypto_mod_put(alg);
   655		kfree_sensitive(tfm->to_free);
   656	}
   657	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [RFC 1/1] crypto: Defer transforms destruction to a worker function
  2023-08-02 17:09 ` [RFC 1/1] crypto: Defer transforms destruction to a worker function Florent Revest
  2023-08-03  6:56   ` kernel test robot
@ 2023-08-03  8:07   ` kernel test robot
  1 sibling, 0 replies; 6+ messages in thread
From: kernel test robot @ 2023-08-03  8:07 UTC (permalink / raw)
  To: Florent Revest; +Cc: llvm, oe-kbuild-all

Hi Florent,

[This is a private test report for your RFC patch.]
kernel test robot noticed the following build warnings:

[auto build test WARNING on herbert-cryptodev-2.6/master]
[also build test WARNING on herbert-crypto-2.6/master linus/master v6.5-rc4 next-20230803]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Florent-Revest/crypto-Defer-transforms-destruction-to-a-worker-function/20230803-011553
base:   https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
patch link:    https://lore.kernel.org/r/20230802170923.1151605-2-revest%40chromium.org
patch subject: [RFC 1/1] crypto: Defer transforms destruction to a worker function
config: um-allnoconfig (https://download.01.org/0day-ci/archive/20230803/202308031541.Oa9qeIe2-lkp@intel.com/config)
compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a)
reproduce: (https://download.01.org/0day-ci/archive/20230803/202308031541.Oa9qeIe2-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202308031541.Oa9qeIe2-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from crypto/api.c:24:
   In file included from crypto/internal.h:21:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/um/include/asm/io.h:24:
   include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     547 |         val = __raw_readb(PCI_IOBASE + addr);
         |                           ~~~~~~~~~~ ^
   include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     560 |         val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu'
      37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
         |                                                   ^
   In file included from crypto/api.c:24:
   In file included from crypto/internal.h:21:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/um/include/asm/io.h:24:
   include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     573 |         val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu'
      35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
         |                                                   ^
   In file included from crypto/api.c:24:
   In file included from crypto/internal.h:21:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/um/include/asm/io.h:24:
   include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     584 |         __raw_writeb(value, PCI_IOBASE + addr);
         |                             ~~~~~~~~~~ ^
   include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     594 |         __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     604 |         __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   include/asm-generic/io.h:692:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     692 |         readsb(PCI_IOBASE + addr, buffer, count);
         |                ~~~~~~~~~~ ^
   include/asm-generic/io.h:700:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     700 |         readsw(PCI_IOBASE + addr, buffer, count);
         |                ~~~~~~~~~~ ^
   include/asm-generic/io.h:708:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     708 |         readsl(PCI_IOBASE + addr, buffer, count);
         |                ~~~~~~~~~~ ^
   include/asm-generic/io.h:717:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     717 |         writesb(PCI_IOBASE + addr, buffer, count);
         |                 ~~~~~~~~~~ ^
   include/asm-generic/io.h:726:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     726 |         writesw(PCI_IOBASE + addr, buffer, count);
         |                 ~~~~~~~~~~ ^
   include/asm-generic/io.h:735:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     735 |         writesl(PCI_IOBASE + addr, buffer, count);
         |                 ~~~~~~~~~~ ^
>> crypto/api.c:643:6: warning: no previous prototype for function 'crypto_destroy_tfm_workfn' [-Wmissing-prototypes]
     643 | void crypto_destroy_tfm_workfn(struct work_struct *w)
         |      ^
   crypto/api.c:643:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
     643 | void crypto_destroy_tfm_workfn(struct work_struct *w)
         | ^
         | static 
   13 warnings generated.


vim +/crypto_destroy_tfm_workfn +643 crypto/api.c

   642	
 > 643	void crypto_destroy_tfm_workfn(struct work_struct *w)
   644	{
   645		struct crypto_alg *alg;
   646		struct crypto_tfm *tfm;
   647	
   648		tfm = container_of(w, struct crypto_tfm, free_work);
   649		alg = tfm->__crt_alg;
   650	
   651		if (!tfm->exit && alg->cra_exit)
   652			alg->cra_exit(tfm);
   653		crypto_exit_ops(tfm);
   654		crypto_mod_put(alg);
   655		kfree_sensitive(tfm->to_free);
   656	}
   657	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 6+ messages in thread

* crypto: api - Use work queue in crypto_destroy_instance
  2023-08-02 17:09 [RFC 0/1] crypto: Avoid a sleepable operation when freeing a SCTP socket Florent Revest
  2023-08-02 17:09 ` [RFC 1/1] crypto: Defer transforms destruction to a worker function Florent Revest
@ 2023-08-03  9:59 ` Herbert Xu
  2023-08-03 12:13   ` Florent Revest
  1 sibling, 1 reply; 6+ messages in thread
From: Herbert Xu @ 2023-08-03  9:59 UTC (permalink / raw)
  To: Florent Revest
  Cc: linux-crypto, linux-kernel, linux-sctp, davem, hillf.zj,
	marcelo.leitner, lucien.xin

On Wed, Aug 02, 2023 at 07:09:22PM +0200, Florent Revest wrote:
> 
> I found that the following program reliably reproduces a "BUG: sleeping function
> called from invalid context" backtrace in crypto code:

Great detective work! And thanks for cc'ing me :)

This is definitely a bug in the Crypto API.  Although it's hard to
trigger because you need to unregister the instance before the last
user frees it in atomic context.  The fact that it triggers for your
test program probably means that we're not creating the template
correctly and it gets unregistered as soon as it's created.

As to the fix I think we should move the work into crypto_destroy_instance
since that's the function that is being called from atomic context
and then does something that should only be done from process context.

So here's my patch based on your work:

---8<---
The function crypto_drop_spawn expects to be called in process
context.  However, when an instance is unregistered while it still
has active users, the last user may cause the instance to be freed
in atomic context.

Fix this by delaying the freeing to a work queue.

Fixes: 6bfd48096ff8 ("[CRYPTO] api: Added spawns")
Reported-by: Florent Revest <revest@chromium.org>
Reported-by: syzbot+d769eed29cc42d75e2a3@syzkaller.appspotmail.com
Reported-by: syzbot+610ec0671f51e838436e@syzkaller.appspotmail.com
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

diff --git a/crypto/algapi.c b/crypto/algapi.c
index 5e7cd603d489..4fe95c448047 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -17,6 +17,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/workqueue.h>
 
 #include "internal.h"
 
@@ -74,15 +75,26 @@ static void crypto_free_instance(struct crypto_instance *inst)
 	inst->alg.cra_type->free(inst);
 }
 
-static void crypto_destroy_instance(struct crypto_alg *alg)
+static void crypto_destroy_instance_workfn(struct work_struct *w)
 {
-	struct crypto_instance *inst = (void *)alg;
+	struct crypto_instance *inst = container_of(w, struct crypto_instance,
+						    free_work);
 	struct crypto_template *tmpl = inst->tmpl;
 
 	crypto_free_instance(inst);
 	crypto_tmpl_put(tmpl);
 }
 
+static void crypto_destroy_instance(struct crypto_alg *alg)
+{
+	struct crypto_instance *inst = container_of(alg,
+						    struct crypto_instance,
+						    alg);
+
+	INIT_WORK(&inst->free_work, crypto_destroy_instance_workfn);
+	schedule_work(&inst->free_work);
+}
+
 /*
  * This function adds a spawn to the list secondary_spawns which
  * will be used at the end of crypto_remove_spawns to unregister
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index 6156161b181f..ca86f4c6ba43 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -12,6 +12,7 @@
 #include <linux/cache.h>
 #include <linux/crypto.h>
 #include <linux/types.h>
+#include <linux/workqueue.h>
 
 /*
  * Maximum values for blocksize and alignmask, used to allocate
@@ -82,6 +83,8 @@ struct crypto_instance {
 		struct crypto_spawn *spawns;
 	};
 
+	struct work_struct free_work;
+
 	void *__ctx[] CRYPTO_MINALIGN_ATTR;
 };
 
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: crypto: api - Use work queue in crypto_destroy_instance
  2023-08-03  9:59 ` crypto: api - Use work queue in crypto_destroy_instance Herbert Xu
@ 2023-08-03 12:13   ` Florent Revest
  0 siblings, 0 replies; 6+ messages in thread
From: Florent Revest @ 2023-08-03 12:13 UTC (permalink / raw)
  To: Herbert Xu
  Cc: linux-crypto, linux-kernel, linux-sctp, davem, hillf.zj,
	marcelo.leitner, lucien.xin

On Thu, Aug 3, 2023 at 11:59 AM Herbert Xu <herbert@gondor.apana.org.au> wrote:
>
> On Wed, Aug 02, 2023 at 07:09:22PM +0200, Florent Revest wrote:
> >
> > I found that the following program reliably reproduces a "BUG: sleeping function
> > called from invalid context" backtrace in crypto code:
>
> Great detective work! And thanks for cc'ing me :)

Thank you!

> This is definitely a bug in the Crypto API.  Although it's hard to
> trigger because you need to unregister the instance before the last
> user frees it in atomic context.  The fact that it triggers for your
> test program probably means that we're not creating the template
> correctly and it gets unregistered as soon as it's created.
>
> As to the fix I think we should move the work into crypto_destroy_instance
> since that's the function that is being called from atomic context
> and then does something that should only be done from process context.

Sounds good to me :)

> So here's my patch based on your work:

FWIW,

Tested-by: Florent Revest <revest@chromium.org>
Acked-by: Florent Revest <revest@chromium.org>

> ---8<---
> The function crypto_drop_spawn expects to be called in process
> context.  However, when an instance is unregistered while it still
> has active users, the last user may cause the instance to be freed
> in atomic context.
>
> Fix this by delaying the freeing to a work queue.
>
> Fixes: 6bfd48096ff8 ("[CRYPTO] api: Added spawns")
> Reported-by: Florent Revest <revest@chromium.org>
> Reported-by: syzbot+d769eed29cc42d75e2a3@syzkaller.appspotmail.com
> Reported-by: syzbot+610ec0671f51e838436e@syzkaller.appspotmail.com
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
>
> diff --git a/crypto/algapi.c b/crypto/algapi.c
> index 5e7cd603d489..4fe95c448047 100644
> --- a/crypto/algapi.c
> +++ b/crypto/algapi.c
> @@ -17,6 +17,7 @@
>  #include <linux/rtnetlink.h>
>  #include <linux/slab.h>
>  #include <linux/string.h>
> +#include <linux/workqueue.h>
>
>  #include "internal.h"
>
> @@ -74,15 +75,26 @@ static void crypto_free_instance(struct crypto_instance *inst)
>         inst->alg.cra_type->free(inst);
>  }
>
> -static void crypto_destroy_instance(struct crypto_alg *alg)
> +static void crypto_destroy_instance_workfn(struct work_struct *w)
>  {
> -       struct crypto_instance *inst = (void *)alg;
> +       struct crypto_instance *inst = container_of(w, struct crypto_instance,
> +                                                   free_work);
>         struct crypto_template *tmpl = inst->tmpl;
>
>         crypto_free_instance(inst);
>         crypto_tmpl_put(tmpl);
>  }
>
> +static void crypto_destroy_instance(struct crypto_alg *alg)
> +{
> +       struct crypto_instance *inst = container_of(alg,
> +                                                   struct crypto_instance,
> +                                                   alg);
> +
> +       INIT_WORK(&inst->free_work, crypto_destroy_instance_workfn);
> +       schedule_work(&inst->free_work);
> +}
> +
>  /*
>   * This function adds a spawn to the list secondary_spawns which
>   * will be used at the end of crypto_remove_spawns to unregister
> diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
> index 6156161b181f..ca86f4c6ba43 100644
> --- a/include/crypto/algapi.h
> +++ b/include/crypto/algapi.h
> @@ -12,6 +12,7 @@
>  #include <linux/cache.h>
>  #include <linux/crypto.h>
>  #include <linux/types.h>
> +#include <linux/workqueue.h>
>
>  /*
>   * Maximum values for blocksize and alignmask, used to allocate
> @@ -82,6 +83,8 @@ struct crypto_instance {
>                 struct crypto_spawn *spawns;
>         };
>
> +       struct work_struct free_work;
> +
>         void *__ctx[] CRYPTO_MINALIGN_ATTR;
>  };

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-08-03 12:13 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-02 17:09 [RFC 0/1] crypto: Avoid a sleepable operation when freeing a SCTP socket Florent Revest
2023-08-02 17:09 ` [RFC 1/1] crypto: Defer transforms destruction to a worker function Florent Revest
2023-08-03  6:56   ` kernel test robot
2023-08-03  8:07   ` kernel test robot
2023-08-03  9:59 ` crypto: api - Use work queue in crypto_destroy_instance Herbert Xu
2023-08-03 12:13   ` Florent Revest

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.