2021-06-18 08:31:49 +03:00
// SPDX-License-Identifier: LGPL-2.1
2011-12-26 22:53:34 +04:00
/*
*
* Copyright ( C ) International Business Machines Corp . , 2002 , 2011
* Etersoft , 2012
* Author ( s ) : Steve French ( sfrench @ us . ibm . com )
* Jeremy Allison ( jra @ samba . org ) 2006
* Pavel Shilovsky ( pshilovsky @ samba . org ) 2012
*
*/
# include <linux/fs.h>
# include <linux/list.h>
# include <linux/wait.h>
# include <linux/net.h>
# include <linux/delay.h>
# include <linux/uaccess.h>
# include <asm/processor.h>
# include <linux/mempool.h>
2012-09-19 03:20:35 +04:00
# include <linux/highmem.h>
2016-11-04 02:47:37 +03:00
# include <crypto/aead.h>
2011-12-26 22:53:34 +04:00
# include "cifsglob.h"
# include "cifsproto.h"
# include "smb2proto.h"
# include "cifs_debug.h"
# include "smb2status.h"
2012-09-19 03:20:30 +04:00
# include "smb2glob.h"
2013-07-04 19:35:21 +04:00
static int
smb3_crypto_shash_allocate ( struct TCP_Server_Info * server )
{
2018-02-16 21:19:27 +03:00
struct cifs_secmech * p = & server - > secmech ;
2013-07-04 19:35:21 +04:00
int rc ;
2018-02-16 21:19:27 +03:00
rc = cifs_alloc_hash ( " hmac(sha256) " ,
& p - > hmacsha256 ,
& p - > sdeschmacsha256 ) ;
2013-07-04 19:35:21 +04:00
if ( rc )
2018-02-16 21:19:27 +03:00
goto err ;
2013-07-04 19:35:21 +04:00
2018-02-16 21:19:27 +03:00
rc = cifs_alloc_hash ( " cmac(aes) " , & p - > cmacaes , & p - > sdesccmacaes ) ;
if ( rc )
goto err ;
2013-07-04 19:35:21 +04:00
return 0 ;
2018-02-16 21:19:27 +03:00
err :
cifs_free_hash ( & p - > hmacsha256 , & p - > sdeschmacsha256 ) ;
return rc ;
2013-07-04 19:35:21 +04:00
}
2018-02-16 21:19:28 +03:00
int
smb311_crypto_shash_allocate ( struct TCP_Server_Info * server )
{
struct cifs_secmech * p = & server - > secmech ;
int rc = 0 ;
rc = cifs_alloc_hash ( " hmac(sha256) " ,
& p - > hmacsha256 ,
& p - > sdeschmacsha256 ) ;
if ( rc )
return rc ;
rc = cifs_alloc_hash ( " cmac(aes) " , & p - > cmacaes , & p - > sdesccmacaes ) ;
if ( rc )
goto err ;
rc = cifs_alloc_hash ( " sha512 " , & p - > sha512 , & p - > sdescsha512 ) ;
if ( rc )
goto err ;
return 0 ;
err :
cifs_free_hash ( & p - > cmacaes , & p - > sdesccmacaes ) ;
cifs_free_hash ( & p - > hmacsha256 , & p - > sdeschmacsha256 ) ;
return rc ;
}
2019-09-20 07:31:10 +03:00
static
int smb2_get_sign_key ( __u64 ses_id , struct TCP_Server_Info * server , u8 * key )
{
struct cifs_chan * chan ;
struct cifs_ses * ses = NULL ;
2020-02-06 15:49:26 +03:00
struct TCP_Server_Info * it = NULL ;
2019-09-20 07:31:10 +03:00
int i ;
int rc = 0 ;
spin_lock ( & cifs_tcp_ses_lock ) ;
2020-02-06 15:49:26 +03:00
list_for_each_entry ( it , & cifs_tcp_ses_list , tcp_ses_list ) {
list_for_each_entry ( ses , & it - > smb_ses_list , smb_ses_list ) {
2019-09-20 07:31:10 +03:00
if ( ses - > Suid = = ses_id )
goto found ;
}
}
cifs_server_dbg ( VFS , " %s: Could not find session 0x%llx \n " ,
__func__ , ses_id ) ;
rc = - ENOENT ;
goto out ;
found :
2021-11-19 17:16:57 +03:00
spin_lock ( & ses - > chan_lock ) ;
2021-07-19 16:54:16 +03:00
if ( cifs_chan_needs_reconnect ( ses , server ) & &
! CIFS_ALL_CHANS_NEED_RECONNECT ( ses ) ) {
2019-09-20 07:31:10 +03:00
/*
* If we are in the process of binding a new channel
* to an existing session , use the master connection
* session key
*/
memcpy ( key , ses - > smb3signingkey , SMB3_SIGN_KEY_SIZE ) ;
2021-11-19 17:16:57 +03:00
spin_unlock ( & ses - > chan_lock ) ;
2019-09-20 07:31:10 +03:00
goto out ;
}
/*
* Otherwise , use the channel key .
*/
for ( i = 0 ; i < ses - > chan_count ; i + + ) {
chan = ses - > chans + i ;
if ( chan - > server = = server ) {
memcpy ( key , chan - > signkey , SMB3_SIGN_KEY_SIZE ) ;
2021-11-19 17:16:57 +03:00
spin_unlock ( & ses - > chan_lock ) ;
2019-09-20 07:31:10 +03:00
goto out ;
}
}
2021-11-19 17:16:57 +03:00
spin_unlock ( & ses - > chan_lock ) ;
2019-09-20 07:31:10 +03:00
cifs_dbg ( VFS ,
" %s: Could not find channel signing key for session 0x%llx \n " ,
__func__ , ses_id ) ;
rc = - ENOENT ;
out :
spin_unlock ( & cifs_tcp_ses_lock ) ;
return rc ;
}
2017-03-04 02:41:38 +03:00
static struct cifs_ses *
smb2_find_smb_ses_unlocked ( struct TCP_Server_Info * server , __u64 ses_id )
2013-08-29 17:35:11 +04:00
{
struct cifs_ses * ses ;
list_for_each_entry ( ses , & server - > smb_ses_list , smb_ses_list ) {
2016-11-04 02:47:37 +03:00
if ( ses - > Suid ! = ses_id )
2013-08-29 17:35:11 +04:00
continue ;
2021-05-23 19:54:42 +03:00
+ + ses - > ses_count ;
2013-08-29 17:35:11 +04:00
return ses ;
}
2017-03-04 02:41:38 +03:00
return NULL ;
}
struct cifs_ses *
smb2_find_smb_ses ( struct TCP_Server_Info * server , __u64 ses_id )
{
struct cifs_ses * ses ;
spin_lock ( & cifs_tcp_ses_lock ) ;
ses = smb2_find_smb_ses_unlocked ( server , ses_id ) ;
2013-08-29 17:35:11 +04:00
spin_unlock ( & cifs_tcp_ses_lock ) ;
2017-03-04 02:41:38 +03:00
return ses ;
}
static struct cifs_tcon *
smb2_find_smb_sess_tcon_unlocked ( struct cifs_ses * ses , __u32 tid )
{
struct cifs_tcon * tcon ;
list_for_each_entry ( tcon , & ses - > tcon_list , tcon_list ) {
if ( tcon - > tid ! = tid )
continue ;
+ + tcon - > tc_count ;
return tcon ;
}
2013-08-29 17:35:11 +04:00
return NULL ;
}
2017-03-04 02:41:38 +03:00
/*
* Obtain tcon corresponding to the tid in the given
* cifs_ses
*/
struct cifs_tcon *
smb2_find_smb_tcon ( struct TCP_Server_Info * server , __u64 ses_id , __u32 tid )
{
struct cifs_ses * ses ;
struct cifs_tcon * tcon ;
spin_lock ( & cifs_tcp_ses_lock ) ;
ses = smb2_find_smb_ses_unlocked ( server , ses_id ) ;
if ( ! ses ) {
spin_unlock ( & cifs_tcp_ses_lock ) ;
return NULL ;
}
tcon = smb2_find_smb_sess_tcon_unlocked ( ses , tid ) ;
2021-05-23 19:54:42 +03:00
if ( ! tcon ) {
cifs_put_smb_ses ( ses ) ;
spin_unlock ( & cifs_tcp_ses_lock ) ;
return NULL ;
}
2017-03-04 02:41:38 +03:00
spin_unlock ( & cifs_tcp_ses_lock ) ;
2021-05-23 19:54:42 +03:00
/* tcon already has a ref to ses, so we don't need ses anymore */
cifs_put_smb_ses ( ses ) ;
2017-03-04 02:41:38 +03:00
return tcon ;
}
2012-12-09 08:08:06 +04:00
int
2020-04-01 02:21:43 +03:00
smb2_calc_signature ( struct smb_rqst * rqst , struct TCP_Server_Info * server ,
bool allocate_crypto )
2012-09-19 03:20:30 +04:00
{
2015-11-13 06:46:49 +03:00
int rc ;
2012-09-19 03:20:30 +04:00
unsigned char smb2_signature [ SMB2_HMACSHA256_SIZE ] ;
unsigned char * sigptr = smb2_signature ;
2012-09-19 03:20:34 +04:00
struct kvec * iov = rqst - > rq_iov ;
2021-11-05 02:39:01 +03:00
struct smb2_hdr * shdr = ( struct smb2_hdr * ) iov [ 0 ] . iov_base ;
2013-08-29 17:35:11 +04:00
struct cifs_ses * ses ;
2018-08-02 17:39:52 +03:00
struct shash_desc * shash ;
2020-04-01 02:21:43 +03:00
struct crypto_shash * hash ;
struct sdesc * sdesc = NULL ;
2018-06-23 20:52:24 +03:00
struct smb_rqst drqst ;
2013-08-29 17:35:11 +04:00
2021-11-05 02:39:01 +03:00
ses = smb2_find_smb_ses ( server , le64_to_cpu ( shdr - > SessionId ) ) ;
2013-08-29 17:35:11 +04:00
if ( ! ses ) {
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: Could not find session \n " , __func__ ) ;
2013-08-29 17:35:11 +04:00
return 0 ;
}
2012-09-19 03:20:30 +04:00
memset ( smb2_signature , 0x0 , SMB2_HMACSHA256_SIZE ) ;
2016-10-25 01:33:04 +03:00
memset ( shdr - > Signature , 0x0 , SMB2_SIGNATURE_SIZE ) ;
2012-09-19 03:20:30 +04:00
2020-04-01 02:21:43 +03:00
if ( allocate_crypto ) {
rc = cifs_alloc_hash ( " hmac(sha256) " , & hash , & sdesc ) ;
if ( rc ) {
cifs_server_dbg ( VFS ,
" %s: sha256 alloc failed \n " , __func__ ) ;
2021-05-23 19:54:42 +03:00
goto out ;
2020-04-01 02:21:43 +03:00
}
shash = & sdesc - > shash ;
} else {
hash = server - > secmech . hmacsha256 ;
shash = & server - > secmech . sdeschmacsha256 - > shash ;
2013-07-04 19:35:21 +04:00
}
2020-04-01 02:21:43 +03:00
rc = crypto_shash_setkey ( hash , ses - > auth_key . response ,
SMB2_NTLMV2_SESSKEY_SIZE ) ;
2012-09-19 03:20:30 +04:00
if ( rc ) {
2020-04-01 02:21:43 +03:00
cifs_server_dbg ( VFS ,
" %s: Could not update with response \n " ,
__func__ ) ;
goto out ;
2012-09-19 03:20:30 +04:00
}
2018-06-23 20:52:24 +03:00
rc = crypto_shash_init ( shash ) ;
2012-09-19 03:20:30 +04:00
if ( rc ) {
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: Could not init sha256 " , __func__ ) ;
2020-04-01 02:21:43 +03:00
goto out ;
2012-09-19 03:20:30 +04:00
}
2018-06-23 20:52:24 +03:00
/*
* For SMB2 + , __cifs_calc_signature ( ) expects to sign only the actual
* data , that is , iov [ 0 ] should not contain a rfc1002 length .
*
* Sign the rfc1002 length prior to passing the data ( iov [ 1 - N ] ) down to
* __cifs_calc_signature ( ) .
*/
drqst = * rqst ;
if ( drqst . rq_nvec > = 2 & & iov [ 0 ] . iov_len = = 4 ) {
rc = crypto_shash_update ( shash , iov [ 0 ] . iov_base ,
iov [ 0 ] . iov_len ) ;
if ( rc ) {
2020-04-01 02:21:43 +03:00
cifs_server_dbg ( VFS ,
" %s: Could not update with payload \n " ,
__func__ ) ;
goto out ;
2018-06-23 20:52:24 +03:00
}
drqst . rq_iov + + ;
drqst . rq_nvec - - ;
}
2012-09-19 03:20:30 +04:00
2018-06-23 20:52:24 +03:00
rc = __cifs_calc_signature ( & drqst , server , sigptr , shash ) ;
2015-11-13 06:46:49 +03:00
if ( ! rc )
2016-10-25 01:33:04 +03:00
memcpy ( shdr - > Signature , sigptr , SMB2_SIGNATURE_SIZE ) ;
2012-09-19 03:20:30 +04:00
2020-04-01 02:21:43 +03:00
out :
if ( allocate_crypto )
cifs_free_hash ( & hash , & sdesc ) ;
2021-05-23 19:54:42 +03:00
if ( ses )
cifs_put_smb_ses ( ses ) ;
2012-09-19 03:20:30 +04:00
return rc ;
}
2015-12-18 22:05:30 +03:00
static int generate_key ( struct cifs_ses * ses , struct kvec label ,
struct kvec context , __u8 * key , unsigned int key_size )
2013-06-27 08:45:05 +04:00
{
unsigned char zero = 0x0 ;
__u8 i [ 4 ] = { 0 , 0 , 0 , 1 } ;
2021-03-25 15:34:54 +03:00
__u8 L128 [ 4 ] = { 0 , 0 , 0 , 128 } ;
__u8 L256 [ 4 ] = { 0 , 0 , 1 , 0 } ;
2013-06-27 08:45:05 +04:00
int rc = 0 ;
unsigned char prfhash [ SMB2_HMACSHA256_SIZE ] ;
unsigned char * hashptr = prfhash ;
2019-08-28 10:15:35 +03:00
struct TCP_Server_Info * server = ses - > server ;
2013-06-27 08:45:05 +04:00
memset ( prfhash , 0x0 , SMB2_HMACSHA256_SIZE ) ;
2015-12-18 22:05:30 +03:00
memset ( key , 0x0 , key_size ) ;
2013-06-27 08:45:05 +04:00
2019-08-28 10:15:35 +03:00
rc = smb3_crypto_shash_allocate ( server ) ;
2013-07-04 19:35:21 +04:00
if ( rc ) {
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: crypto alloc failed \n " , __func__ ) ;
2013-07-04 19:35:21 +04:00
goto smb3signkey_ret ;
}
2019-08-28 10:15:35 +03:00
rc = crypto_shash_setkey ( server - > secmech . hmacsha256 ,
2013-08-29 17:35:11 +04:00
ses - > auth_key . response , SMB2_NTLMV2_SESSKEY_SIZE ) ;
2013-06-27 08:45:05 +04:00
if ( rc ) {
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: Could not set with session key \n " , __func__ ) ;
2013-06-27 08:45:05 +04:00
goto smb3signkey_ret ;
}
2019-08-28 10:15:35 +03:00
rc = crypto_shash_init ( & server - > secmech . sdeschmacsha256 - > shash ) ;
2013-06-27 08:45:05 +04:00
if ( rc ) {
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: Could not init sign hmac \n " , __func__ ) ;
2013-06-27 08:45:05 +04:00
goto smb3signkey_ret ;
}
2019-08-28 10:15:35 +03:00
rc = crypto_shash_update ( & server - > secmech . sdeschmacsha256 - > shash ,
2013-06-27 08:45:05 +04:00
i , 4 ) ;
if ( rc ) {
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: Could not update with n \n " , __func__ ) ;
2013-06-27 08:45:05 +04:00
goto smb3signkey_ret ;
}
2019-08-28 10:15:35 +03:00
rc = crypto_shash_update ( & server - > secmech . sdeschmacsha256 - > shash ,
2015-12-18 22:05:30 +03:00
label . iov_base , label . iov_len ) ;
2013-06-27 08:45:05 +04:00
if ( rc ) {
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: Could not update with label \n " , __func__ ) ;
2013-06-27 08:45:05 +04:00
goto smb3signkey_ret ;
}
2019-08-28 10:15:35 +03:00
rc = crypto_shash_update ( & server - > secmech . sdeschmacsha256 - > shash ,
2013-06-27 08:45:05 +04:00
& zero , 1 ) ;
if ( rc ) {
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: Could not update with zero \n " , __func__ ) ;
2013-06-27 08:45:05 +04:00
goto smb3signkey_ret ;
}
2019-08-28 10:15:35 +03:00
rc = crypto_shash_update ( & server - > secmech . sdeschmacsha256 - > shash ,
2015-12-18 22:05:30 +03:00
context . iov_base , context . iov_len ) ;
2013-06-27 08:45:05 +04:00
if ( rc ) {
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: Could not update with context \n " , __func__ ) ;
2013-06-27 08:45:05 +04:00
goto smb3signkey_ret ;
}
2021-03-25 15:34:54 +03:00
if ( ( server - > cipher_type = = SMB2_ENCRYPTION_AES256_CCM ) | |
( server - > cipher_type = = SMB2_ENCRYPTION_AES256_GCM ) ) {
rc = crypto_shash_update ( & server - > secmech . sdeschmacsha256 - > shash ,
L256 , 4 ) ;
} else {
rc = crypto_shash_update ( & server - > secmech . sdeschmacsha256 - > shash ,
L128 , 4 ) ;
}
2013-06-27 08:45:05 +04:00
if ( rc ) {
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: Could not update with L \n " , __func__ ) ;
2013-06-27 08:45:05 +04:00
goto smb3signkey_ret ;
}
2019-08-28 10:15:35 +03:00
rc = crypto_shash_final ( & server - > secmech . sdeschmacsha256 - > shash ,
2013-06-27 08:45:05 +04:00
hashptr ) ;
if ( rc ) {
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: Could not generate sha256 hash \n " , __func__ ) ;
2013-06-27 08:45:05 +04:00
goto smb3signkey_ret ;
}
2015-12-18 22:05:30 +03:00
memcpy ( key , hashptr , key_size ) ;
2013-06-27 08:45:05 +04:00
smb3signkey_ret :
2013-08-29 17:35:11 +04:00
return rc ;
2013-06-27 08:45:05 +04:00
}
2015-12-18 22:05:30 +03:00
struct derivation {
struct kvec label ;
struct kvec context ;
} ;
struct derivation_triplet {
struct derivation signing ;
struct derivation encryption ;
struct derivation decryption ;
} ;
static int
generate_smb3signingkey ( struct cifs_ses * ses ,
2021-07-19 16:54:16 +03:00
struct TCP_Server_Info * server ,
2015-12-18 22:05:30 +03:00
const struct derivation_triplet * ptriplet )
{
int rc ;
2021-07-19 16:54:16 +03:00
bool is_binding = false ;
int chan_index = 0 ;
spin_lock ( & ses - > chan_lock ) ;
is_binding = ! CIFS_ALL_CHANS_NEED_RECONNECT ( ses ) ;
chan_index = cifs_ses_get_chan_index ( ses , server ) ;
/* TODO: introduce ref counting for channels when the can be freed */
spin_unlock ( & ses - > chan_lock ) ;
2015-12-18 22:05:30 +03:00
2019-09-20 07:31:10 +03:00
/*
* All channels use the same encryption / decryption keys but
* they have their own signing key .
*
* When we generate the keys , check if it is for a new channel
* ( binding ) in which case we only need to generate a signing
* key and store it in the channel as to not overwrite the
* master connection signing key stored in the session
*/
2015-12-18 22:05:30 +03:00
2021-07-19 16:54:16 +03:00
if ( is_binding ) {
2019-09-20 07:31:10 +03:00
rc = generate_key ( ses , ptriplet - > signing . label ,
ptriplet - > signing . context ,
2021-07-19 16:54:16 +03:00
ses - > chans [ chan_index ] . signkey ,
2019-09-20 07:31:10 +03:00
SMB3_SIGN_KEY_SIZE ) ;
if ( rc )
return rc ;
} else {
rc = generate_key ( ses , ptriplet - > signing . label ,
ptriplet - > signing . context ,
ses - > smb3signingkey ,
SMB3_SIGN_KEY_SIZE ) ;
if ( rc )
return rc ;
2019-11-22 18:30:57 +03:00
2021-07-19 16:54:16 +03:00
/* safe to access primary channel, since it will never go away */
2021-11-19 17:16:57 +03:00
spin_lock ( & ses - > chan_lock ) ;
2019-11-22 18:30:57 +03:00
memcpy ( ses - > chans [ 0 ] . signkey , ses - > smb3signingkey ,
SMB3_SIGN_KEY_SIZE ) ;
2021-11-19 17:16:57 +03:00
spin_unlock ( & ses - > chan_lock ) ;
2019-11-22 18:30:57 +03:00
2019-09-20 07:31:10 +03:00
rc = generate_key ( ses , ptriplet - > encryption . label ,
ptriplet - > encryption . context ,
ses - > smb3encryptionkey ,
2021-03-25 15:34:54 +03:00
SMB3_ENC_DEC_KEY_SIZE ) ;
2019-09-20 07:31:10 +03:00
rc = generate_key ( ses , ptriplet - > decryption . label ,
ptriplet - > decryption . context ,
ses - > smb3decryptionkey ,
2021-03-25 15:34:54 +03:00
SMB3_ENC_DEC_KEY_SIZE ) ;
2019-09-20 07:31:10 +03:00
if ( rc )
return rc ;
}
2017-05-24 17:13:25 +03:00
if ( rc )
return rc ;
# ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS
cifs_dbg ( VFS , " %s: dumping generated AES session keys \n " , __func__ ) ;
/*
* The session id is opaque in terms of endianness , so we can ' t
* print it as a long long . we dump it as we got it on the wire
*/
cifs_dbg ( VFS , " Session Id %*ph \n " , ( int ) sizeof ( ses - > Suid ) ,
& ses - > Suid ) ;
2021-03-25 15:34:54 +03:00
cifs_dbg ( VFS , " Cipher type %d \n " , server - > cipher_type ) ;
2017-05-24 17:13:25 +03:00
cifs_dbg ( VFS , " Session Key %*ph \n " ,
SMB2_NTLMV2_SESSKEY_SIZE , ses - > auth_key . response ) ;
cifs_dbg ( VFS , " Signing Key %*ph \n " ,
SMB3_SIGN_KEY_SIZE , ses - > smb3signingkey ) ;
2021-03-25 15:34:54 +03:00
if ( ( server - > cipher_type = = SMB2_ENCRYPTION_AES256_CCM ) | |
( server - > cipher_type = = SMB2_ENCRYPTION_AES256_GCM ) ) {
cifs_dbg ( VFS , " ServerIn Key %*ph \n " ,
SMB3_GCM256_CRYPTKEY_SIZE , ses - > smb3encryptionkey ) ;
cifs_dbg ( VFS , " ServerOut Key %*ph \n " ,
SMB3_GCM256_CRYPTKEY_SIZE , ses - > smb3decryptionkey ) ;
} else {
cifs_dbg ( VFS , " ServerIn Key %*ph \n " ,
SMB3_GCM128_CRYPTKEY_SIZE , ses - > smb3encryptionkey ) ;
cifs_dbg ( VFS , " ServerOut Key %*ph \n " ,
SMB3_GCM128_CRYPTKEY_SIZE , ses - > smb3decryptionkey ) ;
}
2017-05-24 17:13:25 +03:00
# endif
return rc ;
2015-12-18 22:05:30 +03:00
}
int
2021-07-19 16:54:16 +03:00
generate_smb30signingkey ( struct cifs_ses * ses ,
struct TCP_Server_Info * server )
2015-12-18 22:05:30 +03:00
{
struct derivation_triplet triplet ;
struct derivation * d ;
d = & triplet . signing ;
d - > label . iov_base = " SMB2AESCMAC " ;
d - > label . iov_len = 12 ;
d - > context . iov_base = " SmbSign " ;
d - > context . iov_len = 8 ;
d = & triplet . encryption ;
d - > label . iov_base = " SMB2AESCCM " ;
d - > label . iov_len = 11 ;
d - > context . iov_base = " ServerIn " ;
d - > context . iov_len = 10 ;
d = & triplet . decryption ;
d - > label . iov_base = " SMB2AESCCM " ;
d - > label . iov_len = 11 ;
d - > context . iov_base = " ServerOut " ;
d - > context . iov_len = 10 ;
2021-07-19 16:54:16 +03:00
return generate_smb3signingkey ( ses , server , & triplet ) ;
2015-12-18 22:05:30 +03:00
}
int
2021-07-19 16:54:16 +03:00
generate_smb311signingkey ( struct cifs_ses * ses ,
struct TCP_Server_Info * server )
2015-12-18 22:05:30 +03:00
{
struct derivation_triplet triplet ;
struct derivation * d ;
d = & triplet . signing ;
2017-09-26 04:11:58 +03:00
d - > label . iov_base = " SMBSigningKey " ;
d - > label . iov_len = 14 ;
d - > context . iov_base = ses - > preauth_sha_hash ;
d - > context . iov_len = 64 ;
2015-12-18 22:05:30 +03:00
d = & triplet . encryption ;
2017-09-26 04:11:58 +03:00
d - > label . iov_base = " SMBC2SCipherKey " ;
d - > label . iov_len = 16 ;
d - > context . iov_base = ses - > preauth_sha_hash ;
d - > context . iov_len = 64 ;
2015-12-18 22:05:30 +03:00
d = & triplet . decryption ;
2017-09-26 04:11:58 +03:00
d - > label . iov_base = " SMBS2CCipherKey " ;
d - > label . iov_len = 16 ;
d - > context . iov_base = ses - > preauth_sha_hash ;
d - > context . iov_len = 64 ;
2015-12-18 22:05:30 +03:00
2021-07-19 16:54:16 +03:00
return generate_smb3signingkey ( ses , server , & triplet ) ;
2015-12-18 22:05:30 +03:00
}
2012-12-09 08:08:06 +04:00
int
2020-04-01 02:21:43 +03:00
smb3_calc_signature ( struct smb_rqst * rqst , struct TCP_Server_Info * server ,
bool allocate_crypto )
2012-12-09 08:08:06 +04:00
{
2018-06-23 20:52:23 +03:00
int rc ;
2013-06-27 08:45:05 +04:00
unsigned char smb3_signature [ SMB2_CMACAES_SIZE ] ;
unsigned char * sigptr = smb3_signature ;
struct kvec * iov = rqst - > rq_iov ;
2021-11-05 02:39:01 +03:00
struct smb2_hdr * shdr = ( struct smb2_hdr * ) iov [ 0 ] . iov_base ;
2020-04-01 02:21:43 +03:00
struct shash_desc * shash ;
struct crypto_shash * hash ;
struct sdesc * sdesc = NULL ;
2018-06-23 20:52:23 +03:00
struct smb_rqst drqst ;
2019-09-20 07:31:10 +03:00
u8 key [ SMB3_SIGN_KEY_SIZE ] ;
2013-08-29 17:35:11 +04:00
2021-11-05 02:39:01 +03:00
rc = smb2_get_sign_key ( le64_to_cpu ( shdr - > SessionId ) , server , key ) ;
2019-09-20 07:31:10 +03:00
if ( rc )
2013-08-29 17:35:11 +04:00
return 0 ;
2013-06-27 08:45:05 +04:00
2020-04-01 02:21:43 +03:00
if ( allocate_crypto ) {
rc = cifs_alloc_hash ( " cmac(aes) " , & hash , & sdesc ) ;
if ( rc )
return rc ;
shash = & sdesc - > shash ;
} else {
hash = server - > secmech . cmacaes ;
shash = & server - > secmech . sdesccmacaes - > shash ;
}
2013-06-27 08:45:05 +04:00
memset ( smb3_signature , 0x0 , SMB2_CMACAES_SIZE ) ;
2016-10-25 01:33:04 +03:00
memset ( shdr - > Signature , 0x0 , SMB2_SIGNATURE_SIZE ) ;
2013-06-27 08:45:05 +04:00
2020-04-01 02:21:43 +03:00
rc = crypto_shash_setkey ( hash , key , SMB2_CMACAES_SIZE ) ;
2013-06-27 08:45:05 +04:00
if ( rc ) {
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: Could not set key for cmac aes \n " , __func__ ) ;
2020-04-01 02:21:43 +03:00
goto out ;
2013-06-27 08:45:05 +04:00
}
2013-07-04 19:35:21 +04:00
/*
* we already allocate sdesccmacaes when we init smb3 signing key ,
* so unlike smb2 case we do not have to check here if secmech are
* initialized
*/
2018-06-23 20:52:23 +03:00
rc = crypto_shash_init ( shash ) ;
2013-06-27 08:45:05 +04:00
if ( rc ) {
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: Could not init cmac aes \n " , __func__ ) ;
2020-04-01 02:21:43 +03:00
goto out ;
2013-06-27 08:45:05 +04:00
}
2018-02-16 21:19:27 +03:00
2018-06-23 20:52:23 +03:00
/*
* For SMB2 + , __cifs_calc_signature ( ) expects to sign only the actual
* data , that is , iov [ 0 ] should not contain a rfc1002 length .
*
* Sign the rfc1002 length prior to passing the data ( iov [ 1 - N ] ) down to
* __cifs_calc_signature ( ) .
*/
drqst = * rqst ;
if ( drqst . rq_nvec > = 2 & & iov [ 0 ] . iov_len = = 4 ) {
rc = crypto_shash_update ( shash , iov [ 0 ] . iov_base ,
iov [ 0 ] . iov_len ) ;
if ( rc ) {
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: Could not update with payload \n " ,
2018-06-23 20:52:23 +03:00
__func__ ) ;
2020-04-01 02:21:43 +03:00
goto out ;
2018-06-23 20:52:23 +03:00
}
drqst . rq_iov + + ;
drqst . rq_nvec - - ;
}
2013-06-27 08:45:05 +04:00
2018-06-23 20:52:23 +03:00
rc = __cifs_calc_signature ( & drqst , server , sigptr , shash ) ;
2015-11-13 06:46:49 +03:00
if ( ! rc )
2016-10-25 01:33:04 +03:00
memcpy ( shdr - > Signature , sigptr , SMB2_SIGNATURE_SIZE ) ;
2013-06-27 08:45:05 +04:00
2020-04-01 02:21:43 +03:00
out :
if ( allocate_crypto )
cifs_free_hash ( & hash , & sdesc ) ;
2013-06-27 08:45:05 +04:00
return rc ;
2012-12-09 08:08:06 +04:00
}
2012-09-19 03:20:30 +04:00
/* must be called with server->srv_mutex held */
static int
2012-09-19 03:20:34 +04:00
smb2_sign_rqst ( struct smb_rqst * rqst , struct TCP_Server_Info * server )
2012-09-19 03:20:30 +04:00
{
int rc = 0 ;
2021-11-05 02:39:01 +03:00
struct smb2_hdr * shdr ;
2019-09-20 07:31:10 +03:00
struct smb2_sess_setup_req * ssr ;
bool is_binding ;
bool is_signed ;
2012-09-19 03:20:30 +04:00
2021-11-05 02:39:01 +03:00
shdr = ( struct smb2_hdr * ) rqst - > rq_iov [ 0 ] . iov_base ;
2019-09-20 07:31:10 +03:00
ssr = ( struct smb2_sess_setup_req * ) shdr ;
2012-09-19 03:20:30 +04:00
2019-09-20 07:31:10 +03:00
is_binding = shdr - > Command = = SMB2_SESSION_SETUP & &
( ssr - > Flags & SMB2_SESSION_REQ_FLAG_BINDING ) ;
is_signed = shdr - > Flags & SMB2_FLAGS_SIGNED ;
if ( ! is_signed )
return 0 ;
2021-07-19 20:05:53 +03:00
spin_lock ( & cifs_tcp_ses_lock ) ;
2022-03-30 12:22:20 +03:00
if ( server - > ops - > need_neg & &
server - > ops - > need_neg ( server ) ) {
2021-07-19 20:05:53 +03:00
spin_unlock ( & cifs_tcp_ses_lock ) ;
2019-09-20 07:31:10 +03:00
return 0 ;
2021-07-19 20:05:53 +03:00
}
spin_unlock ( & cifs_tcp_ses_lock ) ;
2019-09-20 07:31:10 +03:00
if ( ! is_binding & & ! server - > session_estab ) {
2016-10-25 01:33:04 +03:00
strncpy ( shdr - > Signature , " BSRSPYL " , 8 ) ;
2019-09-20 07:31:10 +03:00
return 0 ;
2012-09-19 03:20:30 +04:00
}
2020-04-01 02:21:43 +03:00
rc = server - > ops - > calc_signature ( rqst , server , false ) ;
2012-09-19 03:20:30 +04:00
return rc ;
}
int
2012-09-19 03:20:34 +04:00
smb2_verify_signature ( struct smb_rqst * rqst , struct TCP_Server_Info * server )
2012-09-19 03:20:30 +04:00
{
unsigned int rc ;
2020-03-27 20:47:41 +03:00
char server_response_sig [ SMB2_SIGNATURE_SIZE ] ;
2021-11-05 02:39:01 +03:00
struct smb2_hdr * shdr =
( struct smb2_hdr * ) rqst - > rq_iov [ 0 ] . iov_base ;
2012-09-19 03:20:30 +04:00
2016-10-25 01:33:04 +03:00
if ( ( shdr - > Command = = SMB2_NEGOTIATE ) | |
( shdr - > Command = = SMB2_SESSION_SETUP ) | |
( shdr - > Command = = SMB2_OPLOCK_BREAK ) | |
2019-09-04 05:18:49 +03:00
server - > ignore_signature | |
2012-09-19 03:20:30 +04:00
( ! server - > session_estab ) )
return 0 ;
/*
* BB what if signatures are supposed to be on for session but
* server does not send one ? BB
*/
/* Do not need to verify session setups with signature "BSRSPYL " */
2016-10-25 01:33:04 +03:00
if ( memcmp ( shdr - > Signature , " BSRSPYL " , 8 ) = = 0 )
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " dummy signature received for smb command 0x%x \n " ,
2016-10-25 01:33:04 +03:00
shdr - > Command ) ;
2012-09-19 03:20:30 +04:00
/*
* Save off the origiginal signature so we can modify the smb and check
* our calculated signature against what the server sent .
*/
2016-10-25 01:33:04 +03:00
memcpy ( server_response_sig , shdr - > Signature , SMB2_SIGNATURE_SIZE ) ;
2012-09-19 03:20:30 +04:00
2016-10-25 01:33:04 +03:00
memset ( shdr - > Signature , 0 , SMB2_SIGNATURE_SIZE ) ;
2012-09-19 03:20:30 +04:00
2020-04-01 02:21:43 +03:00
rc = server - > ops - > calc_signature ( rqst , server , true ) ;
2012-09-19 03:20:30 +04:00
if ( rc )
return rc ;
2020-03-30 00:44:43 +03:00
if ( memcmp ( server_response_sig , shdr - > Signature , SMB2_SIGNATURE_SIZE ) ) {
2020-04-15 09:12:34 +03:00
cifs_dbg ( VFS , " sign fail cmd 0x%x message id 0x%llx \n " ,
shdr - > Command , shdr - > MessageId ) ;
2012-09-19 03:20:30 +04:00
return - EACCES ;
2020-03-30 00:44:43 +03:00
} else
2012-09-19 03:20:30 +04:00
return 0 ;
}
2011-12-26 22:53:34 +04:00
/*
* Set message id for the request . Should be called after wait_for_free_request
* and when srv_mutex is held .
*/
static inline void
2016-10-25 01:33:04 +03:00
smb2_seq_num_into_buf ( struct TCP_Server_Info * server ,
2021-11-05 02:39:01 +03:00
struct smb2_hdr * shdr )
2011-12-26 22:53:34 +04:00
{
2016-10-25 01:33:04 +03:00
unsigned int i , num = le16_to_cpu ( shdr - > CreditCharge ) ;
2014-06-05 19:03:27 +04:00
2016-10-25 01:33:04 +03:00
shdr - > MessageId = get_next_mid64 ( server ) ;
2014-06-05 19:03:27 +04:00
/* skip message numbers according to CreditCharge field */
for ( i = 1 ; i < num ; i + + )
get_next_mid ( server ) ;
2011-12-26 22:53:34 +04:00
}
static struct mid_q_entry *
2021-11-05 02:39:01 +03:00
smb2_mid_entry_alloc ( const struct smb2_hdr * shdr ,
2011-12-26 22:53:34 +04:00
struct TCP_Server_Info * server )
{
struct mid_q_entry * temp ;
2019-03-05 01:02:50 +03:00
unsigned int credits = le16_to_cpu ( shdr - > CreditCharge ) ;
2011-12-26 22:53:34 +04:00
if ( server = = NULL ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( VFS , " Null TCP session in smb2_mid_entry_alloc \n " ) ;
2011-12-26 22:53:34 +04:00
return NULL ;
}
temp = mempool_alloc ( cifs_mid_poolp , GFP_NOFS ) ;
2017-04-10 05:08:53 +03:00
memset ( temp , 0 , sizeof ( struct mid_q_entry ) ) ;
2018-06-25 15:05:25 +03:00
kref_init ( & temp - > refcount ) ;
2017-04-10 05:08:53 +03:00
temp - > mid = le64_to_cpu ( shdr - > MessageId ) ;
2019-03-05 01:02:50 +03:00
temp - > credits = credits > 0 ? credits : 1 ;
2017-04-10 05:08:53 +03:00
temp - > pid = current - > pid ;
temp - > command = shdr - > Command ; /* Always LE */
temp - > when_alloc = jiffies ;
temp - > server = server ;
/*
* The default is for the mid to be synchronous , so the
* default callback just wakes up the current task .
*/
CIFS: Fix task struct use-after-free on reconnect
The task which created the MID may be gone by the time cifsd attempts to
call the callbacks on MIDs from cifs_reconnect().
This leads to a use-after-free of the task struct in cifs_wake_up_task:
==================================================================
BUG: KASAN: use-after-free in __lock_acquire+0x31a0/0x3270
Read of size 8 at addr ffff8880103e3a68 by task cifsd/630
CPU: 0 PID: 630 Comm: cifsd Not tainted 5.5.0-rc6+ #119
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
Call Trace:
dump_stack+0x8e/0xcb
print_address_description.constprop.5+0x1d3/0x3c0
? __lock_acquire+0x31a0/0x3270
__kasan_report+0x152/0x1aa
? __lock_acquire+0x31a0/0x3270
? __lock_acquire+0x31a0/0x3270
kasan_report+0xe/0x20
__lock_acquire+0x31a0/0x3270
? __wake_up_common+0x1dc/0x630
? _raw_spin_unlock_irqrestore+0x4c/0x60
? mark_held_locks+0xf0/0xf0
? _raw_spin_unlock_irqrestore+0x39/0x60
? __wake_up_common_lock+0xd5/0x130
? __wake_up_common+0x630/0x630
lock_acquire+0x13f/0x330
? try_to_wake_up+0xa3/0x19e0
_raw_spin_lock_irqsave+0x38/0x50
? try_to_wake_up+0xa3/0x19e0
try_to_wake_up+0xa3/0x19e0
? cifs_compound_callback+0x178/0x210
? set_cpus_allowed_ptr+0x10/0x10
cifs_reconnect+0xa1c/0x15d0
? generic_ip_connect+0x1860/0x1860
? rwlock_bug.part.0+0x90/0x90
cifs_readv_from_socket+0x479/0x690
cifs_read_from_socket+0x9d/0xe0
? cifs_readv_from_socket+0x690/0x690
? mempool_resize+0x690/0x690
? rwlock_bug.part.0+0x90/0x90
? memset+0x1f/0x40
? allocate_buffers+0xff/0x340
cifs_demultiplex_thread+0x388/0x2a50
? cifs_handle_standard+0x610/0x610
? rcu_read_lock_held_common+0x120/0x120
? mark_lock+0x11b/0xc00
? __lock_acquire+0x14ed/0x3270
? __kthread_parkme+0x78/0x100
? lockdep_hardirqs_on+0x3e8/0x560
? lock_downgrade+0x6a0/0x6a0
? lockdep_hardirqs_on+0x3e8/0x560
? _raw_spin_unlock_irqrestore+0x39/0x60
? cifs_handle_standard+0x610/0x610
kthread+0x2bb/0x3a0
? kthread_create_worker_on_cpu+0xc0/0xc0
ret_from_fork+0x3a/0x50
Allocated by task 649:
save_stack+0x19/0x70
__kasan_kmalloc.constprop.5+0xa6/0xf0
kmem_cache_alloc+0x107/0x320
copy_process+0x17bc/0x5370
_do_fork+0x103/0xbf0
__x64_sys_clone+0x168/0x1e0
do_syscall_64+0x9b/0xec0
entry_SYSCALL_64_after_hwframe+0x49/0xbe
Freed by task 0:
save_stack+0x19/0x70
__kasan_slab_free+0x11d/0x160
kmem_cache_free+0xb5/0x3d0
rcu_core+0x52f/0x1230
__do_softirq+0x24d/0x962
The buggy address belongs to the object at ffff8880103e32c0
which belongs to the cache task_struct of size 6016
The buggy address is located 1960 bytes inside of
6016-byte region [ffff8880103e32c0, ffff8880103e4a40)
The buggy address belongs to the page:
page:ffffea000040f800 refcount:1 mapcount:0 mapping:ffff8880108da5c0
index:0xffff8880103e4c00 compound_mapcount: 0
raw: 4000000000010200 ffffea00001f2208 ffffea00001e3408 ffff8880108da5c0
raw: ffff8880103e4c00 0000000000050003 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff8880103e3900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8880103e3980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff8880103e3a00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff8880103e3a80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8880103e3b00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
This can be reliably reproduced by adding the below delay to
cifs_reconnect(), running find(1) on the mount, restarting the samba
server while find is running, and killing find during the delay:
spin_unlock(&GlobalMid_Lock);
mutex_unlock(&server->srv_mutex);
+ msleep(10000);
+
cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
list_for_each_safe(tmp, tmp2, &retry_list) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
Fix this by holding a reference to the task struct until the MID is
freed.
Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
CC: Stable <stable@vger.kernel.org>
Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
2020-01-23 19:09:06 +03:00
get_task_struct ( current ) ;
temp - > creator = current ;
2017-04-10 05:08:53 +03:00
temp - > callback = cifs_wake_up_task ;
temp - > callback_data = current ;
2011-12-26 22:53:34 +04:00
atomic_inc ( & midCount ) ;
temp - > mid_state = MID_REQUEST_ALLOCATED ;
2021-11-05 02:39:01 +03:00
trace_smb3_cmd_enter ( le32_to_cpu ( shdr - > Id . SyncId . TreeId ) ,
le64_to_cpu ( shdr - > SessionId ) ,
le16_to_cpu ( shdr - > Command ) , temp - > mid ) ;
2011-12-26 22:53:34 +04:00
return temp ;
}
static int
2019-09-20 07:08:34 +03:00
smb2_get_mid_entry ( struct cifs_ses * ses , struct TCP_Server_Info * server ,
2021-11-05 02:39:01 +03:00
struct smb2_hdr * shdr , struct mid_q_entry * * mid )
2011-12-26 22:53:34 +04:00
{
2021-07-19 20:05:53 +03:00
spin_lock ( & cifs_tcp_ses_lock ) ;
if ( server - > tcpStatus = = CifsExiting ) {
spin_unlock ( & cifs_tcp_ses_lock ) ;
2011-12-26 22:53:34 +04:00
return - ENOENT ;
2021-07-19 20:05:53 +03:00
}
2011-12-26 22:53:34 +04:00
2019-09-20 07:08:34 +03:00
if ( server - > tcpStatus = = CifsNeedReconnect ) {
2021-07-19 20:05:53 +03:00
spin_unlock ( & cifs_tcp_ses_lock ) ;
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " tcp session dead - return to caller to retry \n " ) ;
2011-12-26 22:53:34 +04:00
return - EAGAIN ;
}
2019-09-20 07:08:34 +03:00
if ( server - > tcpStatus = = CifsNeedNegotiate & &
2021-07-19 20:05:53 +03:00
shdr - > Command ! = SMB2_NEGOTIATE ) {
spin_unlock ( & cifs_tcp_ses_lock ) ;
2019-03-06 02:51:55 +03:00
return - EAGAIN ;
2021-07-19 20:05:53 +03:00
}
2019-03-06 02:51:55 +03:00
2022-04-07 16:15:49 +03:00
if ( ses - > ses_status = = SES_NEW ) {
2016-10-25 01:33:04 +03:00
if ( ( shdr - > Command ! = SMB2_SESSION_SETUP ) & &
2021-07-19 20:05:53 +03:00
( shdr - > Command ! = SMB2_NEGOTIATE ) ) {
spin_unlock ( & cifs_tcp_ses_lock ) ;
2011-12-26 22:53:34 +04:00
return - EAGAIN ;
2021-07-19 20:05:53 +03:00
}
2011-12-26 22:53:34 +04:00
/* else ok - we are setting up session */
}
2013-10-12 19:06:03 +04:00
2022-04-07 16:15:49 +03:00
if ( ses - > ses_status = = SES_EXITING ) {
2021-07-19 20:05:53 +03:00
if ( shdr - > Command ! = SMB2_LOGOFF ) {
spin_unlock ( & cifs_tcp_ses_lock ) ;
2013-10-12 19:06:03 +04:00
return - EAGAIN ;
2021-07-19 20:05:53 +03:00
}
2013-10-12 19:06:03 +04:00
/* else ok - we are shutting down the session */
}
2021-07-19 20:05:53 +03:00
spin_unlock ( & cifs_tcp_ses_lock ) ;
2013-10-12 19:06:03 +04:00
2019-09-20 07:08:34 +03:00
* mid = smb2_mid_entry_alloc ( shdr , server ) ;
2011-12-26 22:53:34 +04:00
if ( * mid = = NULL )
return - ENOMEM ;
spin_lock ( & GlobalMid_Lock ) ;
2019-09-20 07:08:34 +03:00
list_add_tail ( & ( * mid ) - > qhead , & server - > pending_mid_q ) ;
2011-12-26 22:53:34 +04:00
spin_unlock ( & GlobalMid_Lock ) ;
2019-02-27 06:26:20 +03:00
2011-12-26 22:53:34 +04:00
return 0 ;
}
int
smb2_check_receive ( struct mid_q_entry * mid , struct TCP_Server_Info * server ,
bool log_error )
{
2018-04-09 11:06:28 +03:00
unsigned int len = mid - > resp_buf_size ;
2018-06-01 03:53:02 +03:00
struct kvec iov [ 1 ] ;
2016-11-24 02:14:57 +03:00
struct smb_rqst rqst = { . rq_iov = iov ,
2018-06-01 03:53:02 +03:00
. rq_nvec = 1 } ;
2012-09-19 03:20:34 +04:00
2016-11-24 02:14:57 +03:00
iov [ 0 ] . iov_base = ( char * ) mid - > resp_buf ;
2018-06-01 03:53:02 +03:00
iov [ 0 ] . iov_len = len ;
2011-12-26 22:53:34 +04:00
dump_smb ( mid - > resp_buf , min_t ( u32 , 80 , len ) ) ;
/* convert the length into a more usable form */
2016-11-18 02:24:46 +03:00
if ( len > 24 & & server - > sign & & ! mid - > decrypted ) {
2012-09-19 03:20:30 +04:00
int rc ;
2012-09-19 03:20:34 +04:00
rc = smb2_verify_signature ( & rqst , server ) ;
2012-09-19 03:20:30 +04:00
if ( rc )
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " SMB signature verification returned error = %d \n " ,
2013-05-05 07:12:25 +04:00
rc ) ;
2012-09-19 03:20:30 +04:00
}
2011-12-26 22:53:34 +04:00
return map_smb2_to_linux_error ( mid - > resp_buf , log_error ) ;
}
2012-09-19 03:20:35 +04:00
struct mid_q_entry *
2019-09-20 07:08:34 +03:00
smb2_setup_request ( struct cifs_ses * ses , struct TCP_Server_Info * server ,
struct smb_rqst * rqst )
2011-12-26 22:53:34 +04:00
{
int rc ;
2021-11-05 02:39:01 +03:00
struct smb2_hdr * shdr =
( struct smb2_hdr * ) rqst - > rq_iov [ 0 ] . iov_base ;
2011-12-26 22:53:34 +04:00
struct mid_q_entry * mid ;
2019-09-20 07:08:34 +03:00
smb2_seq_num_into_buf ( server , shdr ) ;
2011-12-26 22:53:34 +04:00
2019-09-20 07:08:34 +03:00
rc = smb2_get_mid_entry ( ses , server , shdr , & mid ) ;
2019-03-05 01:02:50 +03:00
if ( rc ) {
2019-09-20 07:08:34 +03:00
revert_current_mid_from_hdr ( server , shdr ) ;
2012-09-19 03:20:35 +04:00
return ERR_PTR ( rc ) ;
2019-03-05 01:02:50 +03:00
}
2019-09-20 07:08:34 +03:00
rc = smb2_sign_rqst ( rqst , server ) ;
2012-09-19 03:20:35 +04:00
if ( rc ) {
2019-09-20 07:08:34 +03:00
revert_current_mid_from_hdr ( server , shdr ) ;
2012-09-19 03:20:30 +04:00
cifs_delete_mid ( mid ) ;
2012-09-19 03:20:35 +04:00
return ERR_PTR ( rc ) ;
}
2019-03-05 01:02:50 +03:00
2012-09-19 03:20:35 +04:00
return mid ;
2011-12-26 22:53:34 +04:00
}
2012-09-19 03:20:35 +04:00
struct mid_q_entry *
smb2_setup_async_request ( struct TCP_Server_Info * server , struct smb_rqst * rqst )
2012-07-11 14:45:28 +04:00
{
2012-09-19 03:20:35 +04:00
int rc ;
2021-11-05 02:39:01 +03:00
struct smb2_hdr * shdr =
( struct smb2_hdr * ) rqst - > rq_iov [ 0 ] . iov_base ;
2012-07-11 14:45:28 +04:00
struct mid_q_entry * mid ;
2021-07-19 20:05:53 +03:00
spin_lock ( & cifs_tcp_ses_lock ) ;
2019-03-06 02:51:55 +03:00
if ( server - > tcpStatus = = CifsNeedNegotiate & &
2021-07-19 20:05:53 +03:00
shdr - > Command ! = SMB2_NEGOTIATE ) {
spin_unlock ( & cifs_tcp_ses_lock ) ;
2019-03-06 02:51:55 +03:00
return ERR_PTR ( - EAGAIN ) ;
2021-07-19 20:05:53 +03:00
}
spin_unlock ( & cifs_tcp_ses_lock ) ;
2019-03-06 02:51:55 +03:00
2016-10-25 01:33:04 +03:00
smb2_seq_num_into_buf ( server , shdr ) ;
2012-07-11 14:45:28 +04:00
2016-10-25 01:33:04 +03:00
mid = smb2_mid_entry_alloc ( shdr , server ) ;
2019-03-05 01:02:50 +03:00
if ( mid = = NULL ) {
revert_current_mid_from_hdr ( server , shdr ) ;
2012-09-19 03:20:35 +04:00
return ERR_PTR ( - ENOMEM ) ;
2019-03-05 01:02:50 +03:00
}
2012-07-11 14:45:28 +04:00
2012-09-19 03:20:35 +04:00
rc = smb2_sign_rqst ( rqst , server ) ;
2012-07-11 14:45:28 +04:00
if ( rc ) {
2019-03-05 01:02:50 +03:00
revert_current_mid_from_hdr ( server , shdr ) ;
2012-07-11 14:45:28 +04:00
DeleteMidQEntry ( mid ) ;
2012-09-19 03:20:35 +04:00
return ERR_PTR ( rc ) ;
2012-09-19 03:20:30 +04:00
}
2012-09-19 03:20:35 +04:00
return mid ;
2012-07-11 14:45:28 +04:00
}
2016-11-04 02:47:37 +03:00
int
smb3_crypto_aead_allocate ( struct TCP_Server_Info * server )
{
struct crypto_aead * tfm ;
if ( ! server - > secmech . ccmaesencrypt ) {
2020-10-16 07:41:40 +03:00
if ( ( server - > cipher_type = = SMB2_ENCRYPTION_AES128_GCM ) | |
( server - > cipher_type = = SMB2_ENCRYPTION_AES256_GCM ) )
2019-06-07 23:16:10 +03:00
tfm = crypto_alloc_aead ( " gcm(aes) " , 0 , 0 ) ;
else
tfm = crypto_alloc_aead ( " ccm(aes) " , 0 , 0 ) ;
2016-11-04 02:47:37 +03:00
if ( IS_ERR ( tfm ) ) {
2020-10-16 07:41:40 +03:00
cifs_server_dbg ( VFS , " %s: Failed alloc encrypt aead \n " ,
2016-11-04 02:47:37 +03:00
__func__ ) ;
return PTR_ERR ( tfm ) ;
}
server - > secmech . ccmaesencrypt = tfm ;
}
if ( ! server - > secmech . ccmaesdecrypt ) {
2020-10-16 07:41:40 +03:00
if ( ( server - > cipher_type = = SMB2_ENCRYPTION_AES128_GCM ) | |
( server - > cipher_type = = SMB2_ENCRYPTION_AES256_GCM ) )
2019-06-07 23:16:10 +03:00
tfm = crypto_alloc_aead ( " gcm(aes) " , 0 , 0 ) ;
else
tfm = crypto_alloc_aead ( " ccm(aes) " , 0 , 0 ) ;
2016-11-04 02:47:37 +03:00
if ( IS_ERR ( tfm ) ) {
crypto_free_aead ( server - > secmech . ccmaesencrypt ) ;
server - > secmech . ccmaesencrypt = NULL ;
2019-08-28 10:15:35 +03:00
cifs_server_dbg ( VFS , " %s: Failed to alloc decrypt aead \n " ,
2016-11-04 02:47:37 +03:00
__func__ ) ;
return PTR_ERR ( tfm ) ;
}
server - > secmech . ccmaesdecrypt = tfm ;
}
return 0 ;
}