Re: [PATCH] cifs: fix crash due to race in hmac(md5) handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 2016-07-21 at 09:30 +0200, Rabin Vincent wrote:
> On Wed, Jul 20, 2016 at 02:57:29PM +0100, Sachin Prabhu wrote:
> > 
> > Rabin, do you have a reliable reproducer for this case? If yes, can
> > you
> > please point me to it.
> I have only seen one report of the oops in real testing, so I don't
> have
> a case that would reproduce easily on an unmodified kernel, but while
> investigating this I made a debug patch which forces the faulty
> sequence
> to occur and provides a 100% reliable reproducer.
> 
> The below patched forces the race condition by making two mount.cifs
> processes wait for each other in the appropriate places.
> 
> With the force-race patch applied and without this fix, the crash
> occurs
> every time when the following sequence of commands is run.  Tested in
> a
> KVM guest on latest mainline with my "unbreak TCP session reuse"
> patch
> applied.
> 
> With the force-race patch applied and with this fix, the mount
> processes
> hang since the race condition can never be satisfied.


Thanks Rabin.

Sachin Prabhu

> 
>  cp /sbin/mount.cifs /sbin/cifs1
>  cp /sbin/mount.cifs /sbin/cifs2
>  mkdir -p cifs cifs2
>  cifs1 //192.168.1.1/test cifs -o credentials=/creds &
>  sleep 2
>  cifs2 //192.168.1.1/test2 cifs2 -o credentials=/creds
> 
> 8<-------------------------
> diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
> index 8347c90..1ed6dfd 100644
> --- a/fs/cifs/cifsencrypt.c
> +++ b/fs/cifs/cifsencrypt.c
> @@ -35,6 +35,32 @@
>  #include <linux/highmem.h>
>  #include <crypto/skcipher.h>
>  
> +static struct completion completions[100];
> +
> +void hack_set_state(int newstate)
> +{
> +	printk("%s: caller %pF sets state to %d\n", current->comm,
> (void *)_RET_IP_, newstate);
> +	complete(&completions[newstate]);
> +}
> +
> +void hack_wait_for_state(int state)
> +{
> +	printk("%s caller %pF wants state %d\n", current->comm,
> (void *)_RET_IP_, state);
> +	wait_for_completion(&completions[state]);
> +	printk("%s caller %pF got state %d\n", current->comm, (void
> *)_RET_IP_, state);
> +}
> +
> +static int hack_init(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < ARRAY_SIZE(completions); i++)
> +               init_completion(&completions[i]);
> +
> +       return 0;
> +}
> +late_initcall(hack_init);
> +
>  static int
>  cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
>  {
> @@ -54,6 +80,7 @@ cifs_crypto_shash_md5_allocate(struct
> TCP_Server_Info *server)
>  
>  	size = sizeof(struct shash_desc) +
>  			crypto_shash_descsize(server->secmech.md5);
> +
>  	server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
>  	if (!server->secmech.sdescmd5) {
>  		crypto_free_shash(server->secmech.md5);
> @@ -661,8 +688,10 @@ static int crypto_hmacmd5_alloc(struct
> TCP_Server_Info *server)
>  	unsigned int size;
>  
>  	/* check if already allocated */
> -	if (server->secmech.sdeschmacmd5)
> +	if (server->secmech.sdeschmacmd5) {
> +		printk("%s: server %p already allocated\n",
> __func__, server);
>  		return 0;
> +	}
>  
>  	server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0,
> 0);
>  	if (IS_ERR(server->secmech.hmacmd5)) {
> @@ -674,12 +703,28 @@ static int crypto_hmacmd5_alloc(struct
> TCP_Server_Info *server)
>  
>  	size = sizeof(struct shash_desc) +
>  			crypto_shash_descsize(server-
> >secmech.hmacmd5);
> +
> +	if (!strcmp(current->comm, "cifs1")) {
> +		hack_wait_for_state(10);
> +	}
> +	if (!strcmp(current->comm, "cifs2")) {
> +		hack_set_state(10);
> +		hack_wait_for_state(20);
> +	}
> +
>  	server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
> +	printk("%s: %s: server %p alloc sdeschmacmd5=%p\n",
> __func__, current->comm, server, server->secmech.sdeschmacmd5);
>  	if (!server->secmech.sdeschmacmd5) {
>  		crypto_free_shash(server->secmech.hmacmd5);
>  		server->secmech.hmacmd5 = NULL;
>  		return -ENOMEM;
>  	}
> +
> +	if (!strcmp(current->comm, "cifs2")) {
> +		hack_set_state(30);
> +		hack_wait_for_state(40);
> +	}
> +
>  	server->secmech.sdeschmacmd5->shash.tfm = server-
> >secmech.hmacmd5;
>  	server->secmech.sdeschmacmd5->shash.flags = 0x0;
>  
> @@ -745,6 +790,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const
> struct nls_table *nls_cp)
>  
>  	mutex_lock(&ses->server->srv_mutex);
>  
> +	printk("%s: ses %p ses->server %p\n", __func__, ses, ses-
> >server);
>  	rc = crypto_hmacmd5_alloc(ses->server);
>  	if (rc) {
>  		cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc
> %d\n", rc);
> @@ -780,6 +826,11 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const
> struct nls_table *nls_cp)
>  		goto unlock;
>  	}
>  
> +	if (!strcmp(current->comm, "cifs1")) {
> +		hack_set_state(20);
> +		hack_wait_for_state(30);
> +	}
> +
>  	rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5-
> >shash,
>  		ntlmv2->ntlmv2_hash,
>  		CIFS_HMAC_MD5_HASH_SIZE);
> @@ -788,6 +839,8 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const
> struct nls_table *nls_cp)
>  		goto unlock;
>  	}
>  
> +	hack_set_state(40);
> +
>  	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5-
> >shash,
>  		ses->auth_key.response);
>  	if (rc)

--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux