forked from luck/tmp_suning_uos_patched
various SMB3/CIFS fixes for 4.17
-----BEGIN PGP SIGNATURE----- iQGwBAABCAAaBQJaxRzZExxzbWZyZW5jaEBnbWFpbC5jb20ACgkQiiy9cAdyT1Fb FQv/Rd/5CrYhZumBrPvFW2jcbRQ2ANTnSRTA3rpd/jJM52DZ7nvcePr/qm9wRLrT puMfd8e0a4Df5Mo/ns806iphRtYctKpMKLnkBqPL0WqrXLYSi/Nz3wy/DFyuh3C7 U22gDYAjQ4dy6Am0CG/y4i1h8D0hRkmMS6PQECpjmNwqjtmfZn5kWJRv+W5UNNj9 QPldz5PdyNpPw7DxDRetl5uGqUKqsvUATo109hL7ks97qgHUzMHeXWmQpOSS+exh P7tPNphIPJYM2VG+uDvIg15l00lgQxzzN0uOs+x7ZDnZ1Bil/a3So823SfJyXNU2 utJNWSuN/OSHUCmmd7yn+rLd2oJa55+U+Bb3gWaZ8beP639d8P1kEF/isJzu6ede gh92lyU2ecfyHNbjKzAbQwwQxnkmMC5XGhP/2+eawsCyo+vk/NQR4NIehqawj/OB eQSRnT0vNgi4p4OXgJ3FpBBKNBFtTmWrxqKyl0U9C5nw+YdxBdkr16qlFi2b9DjC bW0/ =VW5l -----END PGP SIGNATURE----- Merge tag '4.17-SMB3-Fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull cifs updates from Steve French: "Includes SMB3.11 security improvements, as well as various fixes for stable and some debugging improvements" * tag '4.17-SMB3-Fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: Add minor debug message during negprot smb3: Fix root directory when server returns inode number of zero cifs: fix sparse warning on previous patch in a few printks cifs: add server->vals->header_preamble_size cifs: smbd: disconnect transport on RDMA errors cifs: smbd: avoid reconnect lockup Don't log confusing message on reconnect by default Don't log expected error on DFS referral request fs: cifs: Replace _free_xid call in cifs_root_iget function SMB3.1.1 dialect is no longer experimental Tree connect for SMB3.1.1 must be signed for non-encrypted shares fix smb3-encryption breakage when CONFIG_DEBUG_SG=y CIFS: fix sha512 check in cifs_crypto_secmech_release CIFS: implement v3.11 preauth integrity CIFS: add sha512 secmech CIFS: refactor crypto shash/sdesc allocation&free Update README file for cifs.ko Update TODO list for cifs.ko cifs: fix memory leak in SMB2_open() CIFS: SMBD: fix spelling mistake: "faield" and "legnth"
This commit is contained in:
commit
a8f8e8ac76
|
@ -11,13 +11,14 @@ Information Foundation. CIFS and now SMB3 has now become a defacto
|
|||
standard for interoperating between Macs and Windows and major NAS appliances.
|
||||
|
||||
Please see
|
||||
MS-SMB2 (for detailed SMB2/SMB3/SMB3.1.1 protocol specification)
|
||||
http://protocolfreedom.org/ and
|
||||
http://samba.org/samba/PFIF/
|
||||
for more details.
|
||||
|
||||
|
||||
For questions or bug reports please contact:
|
||||
sfrench@samba.org (sfrench@us.ibm.com)
|
||||
smfrench@gmail.com
|
||||
|
||||
See the project page at: https://wiki.samba.org/index.php/LinuxCIFS_utils
|
||||
|
||||
|
@ -37,15 +38,15 @@ Installation instructions:
|
|||
=========================
|
||||
If you have built the CIFS vfs as module (successfully) simply
|
||||
type "make modules_install" (or if you prefer, manually copy the file to
|
||||
the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o).
|
||||
the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.ko).
|
||||
|
||||
If you have built the CIFS vfs into the kernel itself, follow the instructions
|
||||
for your distribution on how to install a new kernel (usually you
|
||||
would simply type "make install").
|
||||
|
||||
If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on
|
||||
the CIFS VFS web site) copy it to the same directory in which mount.smbfs and
|
||||
similar files reside (usually /sbin). Although the helper software is not
|
||||
If you do not have the utility mount.cifs (in the Samba 4.x source tree and on
|
||||
the CIFS VFS web site) copy it to the same directory in which mount helpers
|
||||
reside (usually /sbin). Although the helper software is not
|
||||
required, mount.cifs is recommended. Most distros include a "cifs-utils"
|
||||
package that includes this utility so it is recommended to install this.
|
||||
|
||||
|
@ -118,10 +119,13 @@ this can become unwieldy when potential mount targets include many
|
|||
or unpredictable UNC names.
|
||||
|
||||
Samba Considerations
|
||||
====================
|
||||
To get the maximum benefit from the CIFS VFS, we recommend using a server that
|
||||
supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or
|
||||
Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers.
|
||||
====================
|
||||
Most current servers support SMB2.1 and SMB3 which are more secure,
|
||||
but there are useful protocol extensions for the older less secure CIFS
|
||||
dialect, so to get the maximum benefit if mounting using the older dialect
|
||||
(CIFS/SMB1), we recommend using a server that supports the SNIA CIFS
|
||||
Unix Extensions standard (e.g. almost any version of Samba ie version
|
||||
2.2.5 or later) but the CIFS vfs works fine with a wide variety of CIFS servers.
|
||||
Note that uid, gid and file permissions will display default values if you do
|
||||
not have a server that supports the Unix extensions for CIFS (such as Samba
|
||||
2.2.5 or later). To enable the Unix CIFS Extensions in the Samba server, add
|
||||
|
@ -603,11 +607,6 @@ Stats Lists summary resource usage information as well as per
|
|||
in the kernel configuration.
|
||||
|
||||
Configuration pseudo-files:
|
||||
PacketSigningEnabled If set to one, cifs packet signing is enabled
|
||||
and will be used if the server requires
|
||||
it. If set to two, cifs packet signing is
|
||||
required even if the server considers packet
|
||||
signing optional. (default 1)
|
||||
SecurityFlags Flags which control security negotiation and
|
||||
also packet signing. Authentication (may/must)
|
||||
flags (e.g. for NTLM and/or NTLMv2) may be combined with
|
||||
|
@ -666,8 +665,6 @@ traceSMB If set to one, debug information is logged to the
|
|||
LookupCacheEnable If set to one, inode information is kept cached
|
||||
for one second improving performance of lookups
|
||||
(default 1)
|
||||
OplockEnabled If set to one, safe distributed caching enabled.
|
||||
(default 1)
|
||||
LinuxExtensionsEnabled If set to one then the client will attempt to
|
||||
use the CIFS "UNIX" extensions which are optional
|
||||
protocol enhancements that allow CIFS servers
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Version 2.04 September 13, 2017
|
||||
Version 2.11 September 13, 2017
|
||||
|
||||
A Partial List of Missing Features
|
||||
==================================
|
||||
|
@ -8,10 +8,10 @@ for visible, important contributions to this module. Here
|
|||
is a partial list of the known problems and missing features:
|
||||
|
||||
a) SMB3 (and SMB3.02) missing optional features:
|
||||
- RDMA (started)
|
||||
- multichannel (started)
|
||||
- multichannel (started), integration with RDMA
|
||||
- directory leases (improved metadata caching)
|
||||
- T10 copy offload (copy chunk is only mechanism supported)
|
||||
- T10 copy offload (copy chunk, and "Duplicate Extents" ioctl
|
||||
currently the only two server side copy mechanisms supported)
|
||||
|
||||
b) improved sparse file support
|
||||
|
||||
|
@ -21,9 +21,8 @@ using Directory Leases
|
|||
d) quota support (needs minor kernel change since quota calls
|
||||
to make it to network filesystems or deviceless filesystems)
|
||||
|
||||
e) Better optimize open to reduce redundant opens (using reference
|
||||
counts more) and to improve use of compounding in SMB3 to reduce
|
||||
number of roundtrips.
|
||||
e) Compounding (in progress) to reduce number of roundtrips, and also
|
||||
better optimize open to reduce redundant opens (using reference counts more).
|
||||
|
||||
f) Finish inotify support so kde and gnome file list windows
|
||||
will autorefresh (partially complete by Asser). Needs minor kernel
|
||||
|
@ -35,7 +34,8 @@ the CIFS statistics (started)
|
|||
h) implement support for security and trusted categories of xattrs
|
||||
(requires minor protocol extension) to enable better support for SELINUX
|
||||
|
||||
i) Implement O_DIRECT flag on open (already supported on mount)
|
||||
i) Add support for tree connect contexts (see MS-SMB2) a new SMB3.1.1 protocol
|
||||
feature (may be especially useful for virtualization).
|
||||
|
||||
j) Create UID mapping facility so server UIDs can be mapped on a per
|
||||
mount or a per server basis to client UIDs or nobody if no mapping
|
||||
|
@ -53,13 +53,16 @@ viewing them.
|
|||
|
||||
o) mount helper GUI (to simplify the various configuration options on mount)
|
||||
|
||||
p) autonegotiation of dialects (offering more than one dialect ie SMB3.02,
|
||||
SMB3, SMB2.1 not just SMB3).
|
||||
p) Add support for witness protocol (perhaps ioctl to cifs.ko from user space
|
||||
tool listening on witness protocol RPC) to allow for notification of share
|
||||
move, server failover, and server adapter changes. And also improve other
|
||||
failover scenarios, e.g. when client knows multiple DFS entries point to
|
||||
different servers, and the server we are connected to has gone down.
|
||||
|
||||
q) Allow mount.cifs to be more verbose in reporting errors with dialect
|
||||
or unsupported feature errors.
|
||||
|
||||
r) updating cifs documentation, and user guid.
|
||||
r) updating cifs documentation, and user guide.
|
||||
|
||||
s) Addressing bugs found by running a broader set of xfstests in standard
|
||||
file system xfstest suite.
|
||||
|
|
|
@ -187,13 +187,13 @@ config CIFS_NFSD_EXPORT
|
|||
Allows NFS server to export a CIFS mounted share (nfsd over cifs)
|
||||
|
||||
config CIFS_SMB311
|
||||
bool "SMB3.1.1 network file system support (Experimental)"
|
||||
bool "SMB3.1.1 network file system support"
|
||||
depends on CIFS
|
||||
select CRYPTO_SHA512
|
||||
|
||||
help
|
||||
This enables experimental support for the newest, SMB3.1.1, dialect.
|
||||
This dialect includes improved security negotiation features.
|
||||
If unsure, say N
|
||||
This enables support for the newest, and most secure dialect, SMB3.11.
|
||||
If unsure, say Y
|
||||
|
||||
config CIFS_SMB_DIRECT
|
||||
bool "SMB Direct support (Experimental)"
|
||||
|
|
|
@ -36,37 +36,6 @@
|
|||
#include <crypto/skcipher.h>
|
||||
#include <crypto/aead.h>
|
||||
|
||||
static int
|
||||
cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
|
||||
{
|
||||
int rc;
|
||||
unsigned int size;
|
||||
|
||||
if (server->secmech.sdescmd5 != NULL)
|
||||
return 0; /* already allocated */
|
||||
|
||||
server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
|
||||
if (IS_ERR(server->secmech.md5)) {
|
||||
cifs_dbg(VFS, "could not allocate crypto md5\n");
|
||||
rc = PTR_ERR(server->secmech.md5);
|
||||
server->secmech.md5 = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
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);
|
||||
server->secmech.md5 = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
|
||||
server->secmech.sdescmd5->shash.flags = 0x0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __cifs_calc_signature(struct smb_rqst *rqst,
|
||||
struct TCP_Server_Info *server, char *signature,
|
||||
struct shash_desc *shash)
|
||||
|
@ -132,13 +101,10 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
|
|||
if (!rqst->rq_iov || !signature || !server)
|
||||
return -EINVAL;
|
||||
|
||||
if (!server->secmech.sdescmd5) {
|
||||
rc = cifs_crypto_shash_md5_allocate(server);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
rc = cifs_alloc_hash("md5", &server->secmech.md5,
|
||||
&server->secmech.sdescmd5);
|
||||
if (rc)
|
||||
return -1;
|
||||
|
||||
rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
|
||||
if (rc) {
|
||||
|
@ -663,37 +629,6 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
|
||||
{
|
||||
int rc;
|
||||
unsigned int size;
|
||||
|
||||
/* check if already allocated */
|
||||
if (server->secmech.sdeschmacmd5)
|
||||
return 0;
|
||||
|
||||
server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
|
||||
if (IS_ERR(server->secmech.hmacmd5)) {
|
||||
cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
|
||||
rc = PTR_ERR(server->secmech.hmacmd5);
|
||||
server->secmech.hmacmd5 = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
size = sizeof(struct shash_desc) +
|
||||
crypto_shash_descsize(server->secmech.hmacmd5);
|
||||
server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
|
||||
if (!server->secmech.sdeschmacmd5) {
|
||||
crypto_free_shash(server->secmech.hmacmd5);
|
||||
server->secmech.hmacmd5 = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
|
||||
server->secmech.sdeschmacmd5->shash.flags = 0x0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
|
||||
{
|
||||
|
@ -757,9 +692,10 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
|
|||
|
||||
mutex_lock(&ses->server->srv_mutex);
|
||||
|
||||
rc = crypto_hmacmd5_alloc(ses->server);
|
||||
rc = cifs_alloc_hash("hmac(md5)",
|
||||
&ses->server->secmech.hmacmd5,
|
||||
&ses->server->secmech.sdeschmacmd5);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
|
@ -893,6 +829,11 @@ cifs_crypto_secmech_release(struct TCP_Server_Info *server)
|
|||
server->secmech.md5 = NULL;
|
||||
}
|
||||
|
||||
if (server->secmech.sha512) {
|
||||
crypto_free_shash(server->secmech.sha512);
|
||||
server->secmech.sha512 = NULL;
|
||||
}
|
||||
|
||||
if (server->secmech.hmacmd5) {
|
||||
crypto_free_shash(server->secmech.hmacmd5);
|
||||
server->secmech.hmacmd5 = NULL;
|
||||
|
@ -916,4 +857,6 @@ cifs_crypto_secmech_release(struct TCP_Server_Info *server)
|
|||
server->secmech.sdeschmacmd5 = NULL;
|
||||
kfree(server->secmech.sdescmd5);
|
||||
server->secmech.sdescmd5 = NULL;
|
||||
kfree(server->secmech.sdescsha512);
|
||||
server->secmech.sdescsha512 = NULL;
|
||||
}
|
||||
|
|
|
@ -1486,6 +1486,7 @@ MODULE_SOFTDEP("pre: nls");
|
|||
MODULE_SOFTDEP("pre: aes");
|
||||
MODULE_SOFTDEP("pre: cmac");
|
||||
MODULE_SOFTDEP("pre: sha256");
|
||||
MODULE_SOFTDEP("pre: sha512");
|
||||
MODULE_SOFTDEP("pre: aead2");
|
||||
MODULE_SOFTDEP("pre: ccm");
|
||||
module_init(init_cifs)
|
||||
|
|
|
@ -130,10 +130,12 @@ struct cifs_secmech {
|
|||
struct crypto_shash *md5; /* md5 hash function */
|
||||
struct crypto_shash *hmacsha256; /* hmac-sha256 hash function */
|
||||
struct crypto_shash *cmacaes; /* block-cipher based MAC function */
|
||||
struct crypto_shash *sha512; /* sha512 hash function */
|
||||
struct sdesc *sdeschmacmd5; /* ctxt to generate ntlmv2 hash, CR1 */
|
||||
struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
|
||||
struct sdesc *sdeschmacsha256; /* ctxt to generate smb2 signature */
|
||||
struct sdesc *sdesccmacaes; /* ctxt to generate smb3 signature */
|
||||
struct sdesc *sdescsha512; /* ctxt to generate smb3.11 signing key */
|
||||
struct crypto_aead *ccmaesencrypt; /* smb3 encryption aead */
|
||||
struct crypto_aead *ccmaesdecrypt; /* smb3 decryption aead */
|
||||
};
|
||||
|
@ -466,6 +468,7 @@ struct smb_version_values {
|
|||
__u32 exclusive_lock_type;
|
||||
__u32 shared_lock_type;
|
||||
__u32 unlock_lock_type;
|
||||
size_t header_preamble_size;
|
||||
size_t header_size;
|
||||
size_t max_header_size;
|
||||
size_t read_rsp_size;
|
||||
|
@ -673,7 +676,8 @@ struct TCP_Server_Info {
|
|||
unsigned int max_read;
|
||||
unsigned int max_write;
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
__u8 preauth_sha_hash[64]; /* save initital negprot hash */
|
||||
/* save initital negprot hash */
|
||||
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
|
||||
#endif /* 3.1.1 */
|
||||
struct delayed_work reconnect; /* reconnect workqueue job */
|
||||
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
|
||||
|
@ -862,7 +866,7 @@ struct cifs_ses {
|
|||
__u8 smb3encryptionkey[SMB3_SIGN_KEY_SIZE];
|
||||
__u8 smb3decryptionkey[SMB3_SIGN_KEY_SIZE];
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
__u8 preauth_sha_hash[64];
|
||||
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
|
||||
#endif /* 3.1.1 */
|
||||
};
|
||||
|
||||
|
@ -1466,6 +1470,7 @@ struct dfs_info3_param {
|
|||
#define CIFS_FATTR_NEED_REVAL 0x4
|
||||
#define CIFS_FATTR_INO_COLLISION 0x8
|
||||
#define CIFS_FATTR_UNKNOWN_NLINK 0x10
|
||||
#define CIFS_FATTR_FAKE_ROOT_INO 0x20
|
||||
|
||||
struct cifs_fattr {
|
||||
u32 cf_flags;
|
||||
|
|
|
@ -542,4 +542,9 @@ enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
|
|||
struct cifs_aio_ctx *cifs_aio_ctx_alloc(void);
|
||||
void cifs_aio_ctx_release(struct kref *refcount);
|
||||
int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw);
|
||||
|
||||
int cifs_alloc_hash(const char *name, struct crypto_shash **shash,
|
||||
struct sdesc **sdesc);
|
||||
void cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc);
|
||||
|
||||
#endif /* _CIFSPROTO_H */
|
||||
|
|
|
@ -1454,7 +1454,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
unsigned int data_offset, data_len;
|
||||
struct cifs_readdata *rdata = mid->callback_data;
|
||||
char *buf = server->smallbuf;
|
||||
unsigned int buflen = get_rfc1002_length(buf) + 4;
|
||||
unsigned int buflen = get_rfc1002_length(buf) +
|
||||
server->vals->header_preamble_size;
|
||||
bool use_rdma_mr = false;
|
||||
|
||||
cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
|
||||
|
@ -1504,7 +1505,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
return cifs_readv_discard(server, mid);
|
||||
}
|
||||
|
||||
data_offset = server->ops->read_data_offset(buf) + 4;
|
||||
data_offset = server->ops->read_data_offset(buf) +
|
||||
server->vals->header_preamble_size;
|
||||
if (data_offset < server->total_read) {
|
||||
/*
|
||||
* win2k8 sometimes sends an offset of 0 when the read
|
||||
|
|
|
@ -775,7 +775,8 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
unsigned int pdu_length = get_rfc1002_length(buf);
|
||||
|
||||
/* make sure this will fit in a large buffer */
|
||||
if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) - 4) {
|
||||
if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
|
||||
server->vals->header_preamble_size) {
|
||||
cifs_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
|
||||
cifs_reconnect(server);
|
||||
wake_up(&server->response_q);
|
||||
|
@ -791,7 +792,9 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
|
||||
/* now read the rest */
|
||||
length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
|
||||
pdu_length - HEADER_SIZE(server) + 1 + 4);
|
||||
pdu_length - HEADER_SIZE(server) + 1
|
||||
+ server->vals->header_preamble_size);
|
||||
|
||||
if (length < 0)
|
||||
return length;
|
||||
server->total_read += length;
|
||||
|
@ -884,7 +887,8 @@ cifs_demultiplex_thread(void *p)
|
|||
continue;
|
||||
|
||||
/* make sure we have enough to get to the MID */
|
||||
if (pdu_length < HEADER_SIZE(server) - 1 - 4) {
|
||||
if (pdu_length < HEADER_SIZE(server) - 1 -
|
||||
server->vals->header_preamble_size) {
|
||||
cifs_dbg(VFS, "SMB response too short (%u bytes)\n",
|
||||
pdu_length);
|
||||
cifs_reconnect(server);
|
||||
|
@ -893,8 +897,10 @@ cifs_demultiplex_thread(void *p)
|
|||
}
|
||||
|
||||
/* read down to the MID */
|
||||
length = cifs_read_from_socket(server, buf + 4,
|
||||
HEADER_SIZE(server) - 1 - 4);
|
||||
length = cifs_read_from_socket(server,
|
||||
buf + server->vals->header_preamble_size,
|
||||
HEADER_SIZE(server) - 1
|
||||
- server->vals->header_preamble_size);
|
||||
if (length < 0)
|
||||
continue;
|
||||
server->total_read += length;
|
||||
|
@ -4306,7 +4312,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
|
|||
server->sec_mode, server->capabilities, server->timeAdj);
|
||||
|
||||
if (ses->auth_key.response) {
|
||||
cifs_dbg(VFS, "Free previous auth_key.response = %p\n",
|
||||
cifs_dbg(FYI, "Free previous auth_key.response = %p\n",
|
||||
ses->auth_key.response);
|
||||
kfree(ses->auth_key.response);
|
||||
ses->auth_key.response = NULL;
|
||||
|
|
|
@ -707,6 +707,18 @@ cifs_get_file_info(struct file *filp)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* Simple function to return a 64 bit hash of string. Rarely called */
|
||||
static __u64 simple_hashstr(const char *str)
|
||||
{
|
||||
const __u64 hash_mult = 1125899906842597L; /* a big enough prime */
|
||||
__u64 hash = 0;
|
||||
|
||||
while (*str)
|
||||
hash = (hash + (__u64) *str++) * hash_mult;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
int
|
||||
cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||
FILE_ALL_INFO *data, struct super_block *sb, int xid,
|
||||
|
@ -816,6 +828,14 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
|
|||
tmprc);
|
||||
fattr.cf_uniqueid = iunique(sb, ROOT_I);
|
||||
cifs_autodisable_serverino(cifs_sb);
|
||||
} else if ((fattr.cf_uniqueid == 0) &&
|
||||
strlen(full_path) == 0) {
|
||||
/* some servers ret bad root ino ie 0 */
|
||||
cifs_dbg(FYI, "Invalid (0) inodenum\n");
|
||||
fattr.cf_flags |=
|
||||
CIFS_FATTR_FAKE_ROOT_INO;
|
||||
fattr.cf_uniqueid =
|
||||
simple_hashstr(tcon->treeName);
|
||||
}
|
||||
}
|
||||
} else
|
||||
|
@ -832,6 +852,16 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
|
|||
&fattr.cf_uniqueid, data);
|
||||
if (tmprc)
|
||||
fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
|
||||
else if ((fattr.cf_uniqueid == 0) &&
|
||||
strlen(full_path) == 0) {
|
||||
/*
|
||||
* Reuse existing root inode num since
|
||||
* inum zero for root causes ls of . and .. to
|
||||
* not be returned
|
||||
*/
|
||||
cifs_dbg(FYI, "Srv ret 0 inode num for root\n");
|
||||
fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
|
||||
}
|
||||
} else
|
||||
fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
|
||||
}
|
||||
|
@ -893,6 +923,9 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
|
|||
}
|
||||
|
||||
cgii_exit:
|
||||
if ((*inode) && ((*inode)->i_ino == 0))
|
||||
cifs_dbg(FYI, "inode number of zero returned\n");
|
||||
|
||||
kfree(buf);
|
||||
cifs_put_tlink(tlink);
|
||||
return rc;
|
||||
|
@ -1066,10 +1099,7 @@ struct inode *cifs_root_iget(struct super_block *sb)
|
|||
|
||||
out:
|
||||
kfree(path);
|
||||
/* can not call macro free_xid here since in a void func
|
||||
* TODO: This is no longer true
|
||||
*/
|
||||
_free_xid(xid);
|
||||
free_xid(xid);
|
||||
return inode;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,25 +50,12 @@ static int
|
|||
symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
|
||||
{
|
||||
int rc;
|
||||
unsigned int size;
|
||||
struct crypto_shash *md5;
|
||||
struct sdesc *sdescmd5;
|
||||
struct crypto_shash *md5 = NULL;
|
||||
struct sdesc *sdescmd5 = NULL;
|
||||
|
||||
md5 = crypto_alloc_shash("md5", 0, 0);
|
||||
if (IS_ERR(md5)) {
|
||||
rc = PTR_ERR(md5);
|
||||
cifs_dbg(VFS, "%s: Crypto md5 allocation error %d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
size = sizeof(struct shash_desc) + crypto_shash_descsize(md5);
|
||||
sdescmd5 = kmalloc(size, GFP_KERNEL);
|
||||
if (!sdescmd5) {
|
||||
rc = -ENOMEM;
|
||||
rc = cifs_alloc_hash("md5", &md5, &sdescmd5);
|
||||
if (rc)
|
||||
goto symlink_hash_err;
|
||||
}
|
||||
sdescmd5->shash.tfm = md5;
|
||||
sdescmd5->shash.flags = 0x0;
|
||||
|
||||
rc = crypto_shash_init(&sdescmd5->shash);
|
||||
if (rc) {
|
||||
|
@ -85,9 +72,7 @@ symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
|
|||
cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
|
||||
|
||||
symlink_hash_err:
|
||||
crypto_free_shash(md5);
|
||||
kfree(sdescmd5);
|
||||
|
||||
cifs_free_hash(&md5, &sdescmd5);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -848,3 +848,57 @@ setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw)
|
|||
iov_iter_bvec(&ctx->iter, ITER_BVEC | rw, ctx->bv, npages, ctx->len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cifs_alloc_hash - allocate hash and hash context together
|
||||
*
|
||||
* The caller has to make sure @sdesc is initialized to either NULL or
|
||||
* a valid context. Both can be freed via cifs_free_hash().
|
||||
*/
|
||||
int
|
||||
cifs_alloc_hash(const char *name,
|
||||
struct crypto_shash **shash, struct sdesc **sdesc)
|
||||
{
|
||||
int rc = 0;
|
||||
size_t size;
|
||||
|
||||
if (*sdesc != NULL)
|
||||
return 0;
|
||||
|
||||
*shash = crypto_alloc_shash(name, 0, 0);
|
||||
if (IS_ERR(*shash)) {
|
||||
cifs_dbg(VFS, "could not allocate crypto %s\n", name);
|
||||
rc = PTR_ERR(*shash);
|
||||
*shash = NULL;
|
||||
*sdesc = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
size = sizeof(struct shash_desc) + crypto_shash_descsize(*shash);
|
||||
*sdesc = kmalloc(size, GFP_KERNEL);
|
||||
if (*sdesc == NULL) {
|
||||
cifs_dbg(VFS, "no memory left to allocate crypto %s\n", name);
|
||||
crypto_free_shash(*shash);
|
||||
*shash = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
(*sdesc)->shash.tfm = *shash;
|
||||
(*sdesc)->shash.flags = 0x0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cifs_free_hash - free hash and hash context together
|
||||
*
|
||||
* Freeing a NULL hash or context is safe.
|
||||
*/
|
||||
void
|
||||
cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc)
|
||||
{
|
||||
kfree(*sdesc);
|
||||
*sdesc = NULL;
|
||||
if (*shash)
|
||||
crypto_free_shash(*shash);
|
||||
*shash = NULL;
|
||||
}
|
||||
|
|
|
@ -1122,6 +1122,7 @@ struct smb_version_values smb1_values = {
|
|||
.exclusive_lock_type = 0,
|
||||
.shared_lock_type = LOCKING_ANDX_SHARED_LOCK,
|
||||
.unlock_lock_type = 0,
|
||||
.header_preamble_size = 4,
|
||||
.header_size = sizeof(struct smb_hdr),
|
||||
.max_header_size = MAX_CIFS_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(READ_RSP),
|
||||
|
|
|
@ -745,7 +745,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
|
|||
"STATUS_NOLOGON_SERVER_TRUST_ACCOUNT"},
|
||||
{STATUS_DOMAIN_TRUST_INCONSISTENT, -EIO,
|
||||
"STATUS_DOMAIN_TRUST_INCONSISTENT"},
|
||||
{STATUS_FS_DRIVER_REQUIRED, -EIO, "STATUS_FS_DRIVER_REQUIRED"},
|
||||
{STATUS_FS_DRIVER_REQUIRED, -EOPNOTSUPP, "STATUS_FS_DRIVER_REQUIRED"},
|
||||
{STATUS_IMAGE_ALREADY_LOADED_AS_DLL, -EIO,
|
||||
"STATUS_IMAGE_ALREADY_LOADED_AS_DLL"},
|
||||
{STATUS_NETWORK_OPEN_RESTRICTION, -EIO,
|
||||
|
|
|
@ -150,7 +150,8 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
|
|||
}
|
||||
return 1;
|
||||
}
|
||||
if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE - 4) {
|
||||
if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE -
|
||||
srvr->vals->header_preamble_size) {
|
||||
cifs_dbg(VFS, "SMB length greater than maximum, mid=%llu\n",
|
||||
mid);
|
||||
return 1;
|
||||
|
@ -189,26 +190,26 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
|
|||
}
|
||||
}
|
||||
|
||||
if (4 + len != length) {
|
||||
cifs_dbg(VFS, "Total length %u RFC1002 length %u mismatch mid %llu\n",
|
||||
length, 4 + len, mid);
|
||||
if (srvr->vals->header_preamble_size + len != length) {
|
||||
cifs_dbg(VFS, "Total length %u RFC1002 length %zu mismatch mid %llu\n",
|
||||
length, srvr->vals->header_preamble_size + len, mid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
clc_len = smb2_calc_size(hdr);
|
||||
|
||||
if (4 + len != clc_len) {
|
||||
cifs_dbg(FYI, "Calculated size %u length %u mismatch mid %llu\n",
|
||||
clc_len, 4 + len, mid);
|
||||
if (srvr->vals->header_preamble_size + len != clc_len) {
|
||||
cifs_dbg(FYI, "Calculated size %u length %zu mismatch mid %llu\n",
|
||||
clc_len, srvr->vals->header_preamble_size + len, mid);
|
||||
/* create failed on symlink */
|
||||
if (command == SMB2_CREATE_HE &&
|
||||
shdr->Status == STATUS_STOPPED_ON_SYMLINK)
|
||||
return 0;
|
||||
/* Windows 7 server returns 24 bytes more */
|
||||
if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
|
||||
if (clc_len + 24 - srvr->vals->header_preamble_size == len && command == SMB2_OPLOCK_BREAK_HE)
|
||||
return 0;
|
||||
/* server can return one byte more due to implied bcc[0] */
|
||||
if (clc_len == 4 + len + 1)
|
||||
if (clc_len == srvr->vals->header_preamble_size + len + 1)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
@ -218,10 +219,10 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
|
|||
* Log the server error (once), but allow it and continue
|
||||
* since the frame is parseable.
|
||||
*/
|
||||
if (clc_len < 4 /* RFC1001 header size */ + len) {
|
||||
if (clc_len < srvr->vals->header_preamble_size /* RFC1001 header size */ + len) {
|
||||
printk_once(KERN_WARNING
|
||||
"SMB2 server sent bad RFC1001 len %d not %d\n",
|
||||
len, clc_len - 4);
|
||||
"SMB2 server sent bad RFC1001 len %d not %zu\n",
|
||||
len, clc_len - srvr->vals->header_preamble_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -706,3 +707,67 @@ smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
/**
|
||||
* smb311_update_preauth_hash - update @ses hash with the packet data in @iov
|
||||
*
|
||||
* Assumes @iov does not contain the rfc1002 length and iov[0] has the
|
||||
* SMB2 header.
|
||||
*/
|
||||
int
|
||||
smb311_update_preauth_hash(struct cifs_ses *ses, struct kvec *iov, int nvec)
|
||||
{
|
||||
int i, rc;
|
||||
struct sdesc *d;
|
||||
struct smb2_sync_hdr *hdr;
|
||||
|
||||
if (ses->server->tcpStatus == CifsGood) {
|
||||
/* skip non smb311 connections */
|
||||
if (ses->server->dialect != SMB311_PROT_ID)
|
||||
return 0;
|
||||
|
||||
/* skip last sess setup response */
|
||||
hdr = (struct smb2_sync_hdr *)iov[0].iov_base;
|
||||
if (hdr->Flags & SMB2_FLAGS_SIGNED)
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = smb311_crypto_shash_allocate(ses->server);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
d = ses->server->secmech.sdescsha512;
|
||||
rc = crypto_shash_init(&d->shash);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: could not init sha512 shash\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = crypto_shash_update(&d->shash, ses->preauth_sha_hash,
|
||||
SMB2_PREAUTH_HASH_SIZE);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: could not update sha512 shash\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
for (i = 0; i < nvec; i++) {
|
||||
rc = crypto_shash_update(&d->shash,
|
||||
iov[i].iov_base, iov[i].iov_len);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: could not update sha512 shash\n",
|
||||
__func__);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
rc = crypto_shash_final(&d->shash, ses->preauth_sha_hash);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: could not finalize sha512 shash\n",
|
||||
__func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1412,7 +1412,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
|
|||
} while (rc == -EAGAIN);
|
||||
|
||||
if (rc) {
|
||||
if (rc != -ENOENT)
|
||||
if ((rc != -ENOENT) && (rc != -EOPNOTSUPP))
|
||||
cifs_dbg(VFS, "ioctl error in smb2_get_dfs_refer rc=%d\n", rc);
|
||||
goto out;
|
||||
}
|
||||
|
@ -1457,6 +1457,8 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
unsigned int sub_offset;
|
||||
unsigned int print_len;
|
||||
unsigned int print_offset;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
|
||||
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
|
||||
|
||||
|
@ -1479,7 +1481,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
}
|
||||
|
||||
if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) ||
|
||||
get_rfc1002_length(err_buf) + 4 < SMB2_SYMLINK_STRUCT_SIZE) {
|
||||
get_rfc1002_length(err_buf) + server->vals->header_preamble_size < SMB2_SYMLINK_STRUCT_SIZE) {
|
||||
kfree(utf16_path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
@ -1492,13 +1494,13 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
print_len = le16_to_cpu(symlink->PrintNameLength);
|
||||
print_offset = le16_to_cpu(symlink->PrintNameOffset);
|
||||
|
||||
if (get_rfc1002_length(err_buf) + 4 <
|
||||
if (get_rfc1002_length(err_buf) + server->vals->header_preamble_size <
|
||||
SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {
|
||||
kfree(utf16_path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (get_rfc1002_length(err_buf) + 4 <
|
||||
if (get_rfc1002_length(err_buf) + server->vals->header_preamble_size <
|
||||
SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) {
|
||||
kfree(utf16_path);
|
||||
return -ENOENT;
|
||||
|
@ -2050,7 +2052,8 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile)
|
|||
}
|
||||
|
||||
static void
|
||||
fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq)
|
||||
fill_transform_hdr(struct TCP_Server_Info *server,
|
||||
struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq)
|
||||
{
|
||||
struct smb2_sync_hdr *shdr =
|
||||
(struct smb2_sync_hdr *)old_rq->rq_iov[1].iov_base;
|
||||
|
@ -2062,10 +2065,19 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq)
|
|||
tr_hdr->Flags = cpu_to_le16(0x01);
|
||||
get_random_bytes(&tr_hdr->Nonce, SMB3_AES128CMM_NONCE);
|
||||
memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8);
|
||||
inc_rfc1001_len(tr_hdr, sizeof(struct smb2_transform_hdr) - 4);
|
||||
inc_rfc1001_len(tr_hdr, sizeof(struct smb2_transform_hdr) - server->vals->header_preamble_size);
|
||||
inc_rfc1001_len(tr_hdr, orig_len);
|
||||
}
|
||||
|
||||
/* We can not use the normal sg_set_buf() as we will sometimes pass a
|
||||
* stack object as buf.
|
||||
*/
|
||||
static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf,
|
||||
unsigned int buflen)
|
||||
{
|
||||
sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf));
|
||||
}
|
||||
|
||||
static struct scatterlist *
|
||||
init_sg(struct smb_rqst *rqst, u8 *sign)
|
||||
{
|
||||
|
@ -2080,16 +2092,16 @@ init_sg(struct smb_rqst *rqst, u8 *sign)
|
|||
return NULL;
|
||||
|
||||
sg_init_table(sg, sg_len);
|
||||
sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len);
|
||||
smb2_sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len);
|
||||
for (i = 1; i < rqst->rq_nvec; i++)
|
||||
sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base,
|
||||
smb2_sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base,
|
||||
rqst->rq_iov[i].iov_len);
|
||||
for (j = 0; i < sg_len - 1; i++, j++) {
|
||||
unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz
|
||||
: rqst->rq_tailsz;
|
||||
sg_set_page(&sg[i], rqst->rq_pages[j], len, 0);
|
||||
}
|
||||
sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE);
|
||||
smb2_sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE);
|
||||
return sg;
|
||||
}
|
||||
|
||||
|
@ -2125,7 +2137,7 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
|
|||
{
|
||||
struct smb2_transform_hdr *tr_hdr =
|
||||
(struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20 - server->vals->header_preamble_size;
|
||||
int rc = 0;
|
||||
struct scatterlist *sg;
|
||||
u8 sign[SMB2_SIGNATURE_SIZE] = {};
|
||||
|
@ -2253,7 +2265,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
|
|||
goto err_free_iov;
|
||||
|
||||
/* fill the 1st iov with a transform header */
|
||||
fill_transform_hdr(tr_hdr, old_rq);
|
||||
fill_transform_hdr(server, tr_hdr, old_rq);
|
||||
new_rq->rq_iov[0].iov_base = tr_hdr;
|
||||
new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr);
|
||||
|
||||
|
@ -2335,10 +2347,10 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
memmove(buf + 4, iov[1].iov_base, buf_data_size);
|
||||
memmove(buf + server->vals->header_preamble_size, iov[1].iov_base, buf_data_size);
|
||||
hdr = (struct smb2_hdr *)buf;
|
||||
hdr->smb2_buf_length = cpu_to_be32(buf_data_size + page_data_size);
|
||||
server->total_read = buf_data_size + page_data_size + 4;
|
||||
server->total_read = buf_data_size + page_data_size + server->vals->header_preamble_size;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -2442,7 +2454,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|||
return 0;
|
||||
}
|
||||
|
||||
data_offset = server->ops->read_data_offset(buf) + 4;
|
||||
data_offset = server->ops->read_data_offset(buf) + server->vals->header_preamble_size;
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
use_rdma_mr = rdata->mr;
|
||||
#endif
|
||||
|
@ -2538,11 +2550,12 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
|||
unsigned int npages;
|
||||
struct page **pages;
|
||||
unsigned int len;
|
||||
unsigned int buflen = get_rfc1002_length(buf) + 4;
|
||||
unsigned int buflen = get_rfc1002_length(buf) + server->vals->header_preamble_size;
|
||||
int rc;
|
||||
int i = 0;
|
||||
|
||||
len = min_t(unsigned int, buflen, server->vals->read_rsp_size - 4 +
|
||||
len = min_t(unsigned int, buflen, server->vals->read_rsp_size -
|
||||
server->vals->header_preamble_size +
|
||||
sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
|
||||
|
||||
rc = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, len);
|
||||
|
@ -2550,8 +2563,9 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
|||
return rc;
|
||||
server->total_read += rc;
|
||||
|
||||
len = le32_to_cpu(tr_hdr->OriginalMessageSize) + 4 -
|
||||
server->vals->read_rsp_size;
|
||||
len = le32_to_cpu(tr_hdr->OriginalMessageSize) +
|
||||
server->vals->header_preamble_size -
|
||||
server->vals->read_rsp_size;
|
||||
npages = DIV_ROUND_UP(len, PAGE_SIZE);
|
||||
|
||||
pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
|
||||
|
@ -2577,7 +2591,8 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
|||
if (rc)
|
||||
goto free_pages;
|
||||
|
||||
rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size - 4,
|
||||
rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size -
|
||||
server->vals->header_preamble_size,
|
||||
pages, npages, len);
|
||||
if (rc)
|
||||
goto free_pages;
|
||||
|
@ -2614,7 +2629,7 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
|
|||
struct mid_q_entry *mid_entry;
|
||||
|
||||
/* switch to large buffer if too big for a small one */
|
||||
if (pdu_length + 4 > MAX_CIFS_SMALL_BUFFER_SIZE) {
|
||||
if (pdu_length + server->vals->header_preamble_size > MAX_CIFS_SMALL_BUFFER_SIZE) {
|
||||
server->large_buf = true;
|
||||
memcpy(server->bigbuf, buf, server->total_read);
|
||||
buf = server->bigbuf;
|
||||
|
@ -2622,12 +2637,13 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
|
|||
|
||||
/* now read the rest */
|
||||
length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
|
||||
pdu_length - HEADER_SIZE(server) + 1 + 4);
|
||||
pdu_length - HEADER_SIZE(server) + 1 +
|
||||
server->vals->header_preamble_size);
|
||||
if (length < 0)
|
||||
return length;
|
||||
server->total_read += length;
|
||||
|
||||
buf_size = pdu_length + 4 - sizeof(struct smb2_transform_hdr);
|
||||
buf_size = pdu_length + server->vals->header_preamble_size - sizeof(struct smb2_transform_hdr);
|
||||
length = decrypt_raw_data(server, buf, buf_size, NULL, 0, 0);
|
||||
if (length)
|
||||
return length;
|
||||
|
@ -2656,7 +2672,7 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
|||
struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
|
||||
unsigned int orig_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
|
||||
|
||||
if (pdu_length + 4 < sizeof(struct smb2_transform_hdr) +
|
||||
if (pdu_length + server->vals->header_preamble_size < sizeof(struct smb2_transform_hdr) +
|
||||
sizeof(struct smb2_sync_hdr)) {
|
||||
cifs_dbg(VFS, "Transform message is too small (%u)\n",
|
||||
pdu_length);
|
||||
|
@ -2665,14 +2681,14 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
|||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
if (pdu_length + 4 < orig_len + sizeof(struct smb2_transform_hdr)) {
|
||||
if (pdu_length + server->vals->header_preamble_size < orig_len + sizeof(struct smb2_transform_hdr)) {
|
||||
cifs_dbg(VFS, "Transform message is broken\n");
|
||||
cifs_reconnect(server);
|
||||
wake_up(&server->response_q);
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
if (pdu_length + 4 > CIFSMaxBufSize + MAX_HEADER_SIZE(server))
|
||||
if (pdu_length + server->vals->header_preamble_size > CIFSMaxBufSize + MAX_HEADER_SIZE(server))
|
||||
return receive_encrypted_read(server, mid);
|
||||
|
||||
return receive_encrypted_standard(server, mid);
|
||||
|
@ -2683,7 +2699,8 @@ smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
{
|
||||
char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
|
||||
|
||||
return handle_read_data(server, mid, buf, get_rfc1002_length(buf) + 4,
|
||||
return handle_read_data(server, mid, buf, get_rfc1002_length(buf) +
|
||||
server->vals->header_preamble_size,
|
||||
NULL, 0, 0);
|
||||
}
|
||||
|
||||
|
@ -3088,6 +3105,7 @@ struct smb_version_values smb20_values = {
|
|||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 4,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
@ -3108,6 +3126,7 @@ struct smb_version_values smb21_values = {
|
|||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 4,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
@ -3128,6 +3147,7 @@ struct smb_version_values smb3any_values = {
|
|||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 4,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
@ -3148,6 +3168,7 @@ struct smb_version_values smbdefault_values = {
|
|||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 4,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
@ -3168,6 +3189,7 @@ struct smb_version_values smb30_values = {
|
|||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 4,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
@ -3188,6 +3210,7 @@ struct smb_version_values smb302_values = {
|
|||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 4,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
@ -3209,6 +3232,7 @@ struct smb_version_values smb311_values = {
|
|||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 4,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
|
|
@ -453,6 +453,10 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||
return rc;
|
||||
|
||||
req->sync_hdr.SessionId = 0;
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
memset(server->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE);
|
||||
memset(ses->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE);
|
||||
#endif
|
||||
|
||||
if (strcmp(ses->server->vals->version_string,
|
||||
SMB3ANY_VERSION_STRING) == 0) {
|
||||
|
@ -564,6 +568,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||
|
||||
/* BB: add check that dialect was valid given dialect(s) we asked for */
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
/*
|
||||
* Keep a copy of the hash after negprot. This hash will be
|
||||
* the starting hash value for all sessions made from this
|
||||
* server.
|
||||
*/
|
||||
memcpy(server->preauth_sha_hash, ses->preauth_sha_hash,
|
||||
SMB2_PREAUTH_HASH_SIZE);
|
||||
#endif
|
||||
/* SMB2 only has an extended negflavor */
|
||||
server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
|
||||
/* set it to the maximum buffer size value we can send with 1 credit */
|
||||
|
@ -571,8 +584,10 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||
SMB2_MAX_BUFFER_SIZE);
|
||||
server->max_read = le32_to_cpu(rsp->MaxReadSize);
|
||||
server->max_write = le32_to_cpu(rsp->MaxWriteSize);
|
||||
/* BB Do we need to validate the SecurityMode? */
|
||||
server->sec_mode = le16_to_cpu(rsp->SecurityMode);
|
||||
if ((server->sec_mode & SMB2_SEC_MODE_FLAGS_ALL) != server->sec_mode)
|
||||
cifs_dbg(FYI, "Server returned unexpected security mode 0x%x\n",
|
||||
server->sec_mode);
|
||||
server->capabilities = le32_to_cpu(rsp->Capabilities);
|
||||
/* Internal types */
|
||||
server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES;
|
||||
|
@ -621,6 +636,10 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
|
|||
return 0;
|
||||
#endif
|
||||
|
||||
/* In SMB3.11 preauth integrity supersedes validate negotiate */
|
||||
if (tcon->ses->server->dialect == SMB311_PROT_ID)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* validation ioctl must be signed, so no point sending this if we
|
||||
* can not sign it (ie are not known user). Even if signing is not
|
||||
|
@ -1148,6 +1167,14 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
|
|||
sess_data->buf0_type = CIFS_NO_BUFFER;
|
||||
sess_data->nls_cp = (struct nls_table *) nls_cp;
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
/*
|
||||
* Initialize the session hash with the server one.
|
||||
*/
|
||||
memcpy(ses->preauth_sha_hash, ses->server->preauth_sha_hash,
|
||||
SMB2_PREAUTH_HASH_SIZE);
|
||||
#endif
|
||||
|
||||
while (sess_data->func)
|
||||
sess_data->func(sess_data);
|
||||
|
||||
|
@ -1280,6 +1307,11 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
|
|||
iov[1].iov_base = unc_path;
|
||||
iov[1].iov_len = unc_path_len;
|
||||
|
||||
/* 3.11 tcon req must be signed if not encrypted. See MS-SMB2 3.2.4.1.1 */
|
||||
if ((ses->server->dialect == SMB311_PROT_ID) &&
|
||||
!encryption_required(tcon))
|
||||
req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED;
|
||||
|
||||
rc = smb2_send_recv(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov);
|
||||
cifs_small_buf_release(req);
|
||||
rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base;
|
||||
|
@ -1441,7 +1473,7 @@ parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp,
|
|||
unsigned int remaining;
|
||||
char *name;
|
||||
|
||||
data_offset = (char *)rsp + 4 + le32_to_cpu(rsp->CreateContextsOffset);
|
||||
data_offset = (char *)rsp + server->vals->header_preamble_size + le32_to_cpu(rsp->CreateContextsOffset);
|
||||
remaining = le32_to_cpu(rsp->CreateContextsLength);
|
||||
cc = (struct create_context *)data_offset;
|
||||
while (remaining >= sizeof(struct create_context)) {
|
||||
|
@ -1738,8 +1770,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
rc = alloc_path_with_tree_prefix(©_path, ©_size,
|
||||
&name_len,
|
||||
tcon->treeName, path);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
cifs_small_buf_release(req);
|
||||
return rc;
|
||||
}
|
||||
req->NameLength = cpu_to_le16(name_len * 2);
|
||||
uni_path_len = copy_size;
|
||||
path = copy_path;
|
||||
|
@ -1750,8 +1784,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
if (uni_path_len % 8 != 0) {
|
||||
copy_size = roundup(uni_path_len, 8);
|
||||
copy_path = kzalloc(copy_size, GFP_KERNEL);
|
||||
if (!copy_path)
|
||||
if (!copy_path) {
|
||||
cifs_small_buf_release(req);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy((char *)copy_path, (const char *)path,
|
||||
uni_path_len);
|
||||
uni_path_len = copy_size;
|
||||
|
@ -3418,6 +3454,7 @@ static int
|
|||
build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
|
||||
int outbuf_len, u64 persistent_fid, u64 volatile_fid)
|
||||
{
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
int rc;
|
||||
struct smb2_query_info_req *req;
|
||||
unsigned int total_len;
|
||||
|
@ -3440,7 +3477,7 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
|
|||
req->InputBufferOffset =
|
||||
cpu_to_le16(sizeof(struct smb2_query_info_req) - 1);
|
||||
req->OutputBufferLength = cpu_to_le32(
|
||||
outbuf_len + sizeof(struct smb2_query_info_rsp) - 1 - 4);
|
||||
outbuf_len + sizeof(struct smb2_query_info_rsp) - 1 - server->vals->header_preamble_size);
|
||||
|
||||
iov->iov_base = (char *)req;
|
||||
iov->iov_len = total_len;
|
||||
|
@ -3457,6 +3494,7 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
int rc = 0;
|
||||
int resp_buftype;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
struct smb2_fs_full_size_info *info = NULL;
|
||||
int flags = 0;
|
||||
|
||||
|
@ -3477,7 +3515,7 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
}
|
||||
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
|
||||
|
||||
info = (struct smb2_fs_full_size_info *)(4 /* RFC1001 len */ +
|
||||
info = (struct smb2_fs_full_size_info *)(server->vals->header_preamble_size +
|
||||
le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr);
|
||||
rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr,
|
||||
|
@ -3500,6 +3538,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
int rc = 0;
|
||||
int resp_buftype, max_len, min_len;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
unsigned int rsp_len, offset;
|
||||
int flags = 0;
|
||||
|
||||
|
@ -3540,15 +3579,15 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
goto qfsattr_exit;
|
||||
|
||||
if (level == FS_ATTRIBUTE_INFORMATION)
|
||||
memcpy(&tcon->fsAttrInfo, 4 /* RFC1001 len */ + offset
|
||||
memcpy(&tcon->fsAttrInfo, server->vals->header_preamble_size + offset
|
||||
+ (char *)&rsp->hdr, min_t(unsigned int,
|
||||
rsp_len, max_len));
|
||||
else if (level == FS_DEVICE_INFORMATION)
|
||||
memcpy(&tcon->fsDevInfo, 4 /* RFC1001 len */ + offset
|
||||
memcpy(&tcon->fsDevInfo, server->vals->header_preamble_size + offset
|
||||
+ (char *)&rsp->hdr, sizeof(FILE_SYSTEM_DEVICE_INFO));
|
||||
else if (level == FS_SECTOR_SIZE_INFORMATION) {
|
||||
struct smb3_fs_ss_info *ss_info = (struct smb3_fs_ss_info *)
|
||||
(4 /* RFC1001 len */ + offset + (char *)&rsp->hdr);
|
||||
(server->vals->header_preamble_size + offset + (char *)&rsp->hdr);
|
||||
tcon->ss_flags = le32_to_cpu(ss_info->Flags);
|
||||
tcon->perf_sector_size =
|
||||
le32_to_cpu(ss_info->PhysicalBytesPerSectorForPerf);
|
||||
|
|
|
@ -249,6 +249,8 @@ struct smb2_negotiate_req {
|
|||
/* SecurityMode flags */
|
||||
#define SMB2_NEGOTIATE_SIGNING_ENABLED 0x0001
|
||||
#define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x0002
|
||||
#define SMB2_SEC_MODE_FLAGS_ALL 0x0003
|
||||
|
||||
/* Capabilities flags */
|
||||
#define SMB2_GLOBAL_CAP_DFS 0x00000001
|
||||
#define SMB2_GLOBAL_CAP_LEASING 0x00000002 /* Resp only New to SMB2.1 */
|
||||
|
@ -264,6 +266,7 @@ struct smb2_negotiate_req {
|
|||
#define SMB311_SALT_SIZE 32
|
||||
/* Hash Algorithm Types */
|
||||
#define SMB2_PREAUTH_INTEGRITY_SHA512 cpu_to_le16(0x0001)
|
||||
#define SMB2_PREAUTH_HASH_SIZE 64
|
||||
|
||||
struct smb2_preauth_neg_context {
|
||||
__le16 ContextType; /* 1 */
|
||||
|
|
|
@ -202,4 +202,9 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *);
|
|||
|
||||
extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
|
||||
enum securityEnum);
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server);
|
||||
extern int smb311_update_preauth_hash(struct cifs_ses *ses,
|
||||
struct kvec *iov, int nvec);
|
||||
#endif
|
||||
#endif /* _SMB2PROTO_H */
|
||||
|
|
|
@ -43,77 +43,62 @@
|
|||
static int
|
||||
smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
|
||||
{
|
||||
int rc;
|
||||
unsigned int size;
|
||||
|
||||
if (server->secmech.sdeschmacsha256 != NULL)
|
||||
return 0; /* already allocated */
|
||||
|
||||
server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
|
||||
if (IS_ERR(server->secmech.hmacsha256)) {
|
||||
cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
|
||||
rc = PTR_ERR(server->secmech.hmacsha256);
|
||||
server->secmech.hmacsha256 = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
size = sizeof(struct shash_desc) +
|
||||
crypto_shash_descsize(server->secmech.hmacsha256);
|
||||
server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
|
||||
if (!server->secmech.sdeschmacsha256) {
|
||||
crypto_free_shash(server->secmech.hmacsha256);
|
||||
server->secmech.hmacsha256 = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
|
||||
server->secmech.sdeschmacsha256->shash.flags = 0x0;
|
||||
|
||||
return 0;
|
||||
return cifs_alloc_hash("hmac(sha256)",
|
||||
&server->secmech.hmacsha256,
|
||||
&server->secmech.sdeschmacsha256);
|
||||
}
|
||||
|
||||
static int
|
||||
smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
|
||||
{
|
||||
unsigned int size;
|
||||
struct cifs_secmech *p = &server->secmech;
|
||||
int rc;
|
||||
|
||||
if (server->secmech.sdesccmacaes != NULL)
|
||||
return 0; /* already allocated */
|
||||
rc = cifs_alloc_hash("hmac(sha256)",
|
||||
&p->hmacsha256,
|
||||
&p->sdeschmacsha256);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = smb2_crypto_shash_allocate(server);
|
||||
rc = cifs_alloc_hash("cmac(aes)", &p->cmacaes, &p->sdesccmacaes);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
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;
|
||||
|
||||
server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
|
||||
if (IS_ERR(server->secmech.cmacaes)) {
|
||||
cifs_dbg(VFS, "could not allocate crypto cmac-aes");
|
||||
kfree(server->secmech.sdeschmacsha256);
|
||||
server->secmech.sdeschmacsha256 = NULL;
|
||||
crypto_free_shash(server->secmech.hmacsha256);
|
||||
server->secmech.hmacsha256 = NULL;
|
||||
rc = PTR_ERR(server->secmech.cmacaes);
|
||||
server->secmech.cmacaes = NULL;
|
||||
return rc;
|
||||
}
|
||||
rc = cifs_alloc_hash("cmac(aes)", &p->cmacaes, &p->sdesccmacaes);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
size = sizeof(struct shash_desc) +
|
||||
crypto_shash_descsize(server->secmech.cmacaes);
|
||||
server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
|
||||
if (!server->secmech.sdesccmacaes) {
|
||||
cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
|
||||
kfree(server->secmech.sdeschmacsha256);
|
||||
server->secmech.sdeschmacsha256 = NULL;
|
||||
crypto_free_shash(server->secmech.hmacsha256);
|
||||
crypto_free_shash(server->secmech.cmacaes);
|
||||
server->secmech.hmacsha256 = NULL;
|
||||
server->secmech.cmacaes = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
|
||||
server->secmech.sdesccmacaes->shash.flags = 0x0;
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct cifs_ses *
|
||||
smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
|
||||
|
@ -457,7 +442,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||
cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
rc = __cifs_calc_signature(rqst, server, sigptr,
|
||||
&server->secmech.sdesccmacaes->shash);
|
||||
|
||||
|
|
|
@ -862,6 +862,8 @@ static int smbd_post_send_negotiate_req(struct smbd_connection *info)
|
|||
ib_dma_unmap_single(info->id->device, request->sge[0].addr,
|
||||
request->sge[0].length, DMA_TO_DEVICE);
|
||||
|
||||
smbd_disconnect_rdma_connection(info);
|
||||
|
||||
dma_mapping_failed:
|
||||
mempool_free(request, info->request_mempool);
|
||||
return rc;
|
||||
|
@ -1025,7 +1027,7 @@ static int smbd_post_send(struct smbd_connection *info,
|
|||
|
||||
for (i = 0; i < request->num_sge; i++) {
|
||||
log_rdma_send(INFO,
|
||||
"rdma_request sge[%d] addr=%llu legnth=%u\n",
|
||||
"rdma_request sge[%d] addr=%llu length=%u\n",
|
||||
i, request->sge[0].addr, request->sge[0].length);
|
||||
ib_dma_sync_single_for_device(
|
||||
info->id->device,
|
||||
|
@ -1061,6 +1063,7 @@ static int smbd_post_send(struct smbd_connection *info,
|
|||
if (atomic_dec_and_test(&info->send_pending))
|
||||
wake_up(&info->wait_send_pending);
|
||||
}
|
||||
smbd_disconnect_rdma_connection(info);
|
||||
} else
|
||||
/* Reset timer for idle connection after packet is sent */
|
||||
mod_delayed_work(info->workqueue, &info->idle_timer_work,
|
||||
|
@ -1202,7 +1205,7 @@ static int smbd_post_recv(
|
|||
if (rc) {
|
||||
ib_dma_unmap_single(info->id->device, response->sge.addr,
|
||||
response->sge.length, DMA_FROM_DEVICE);
|
||||
|
||||
smbd_disconnect_rdma_connection(info);
|
||||
log_rdma_recv(ERR, "ib_post_recv failed rc=%d\n", rc);
|
||||
}
|
||||
|
||||
|
@ -1498,8 +1501,8 @@ int smbd_reconnect(struct TCP_Server_Info *server)
|
|||
log_rdma_event(INFO, "reconnecting rdma session\n");
|
||||
|
||||
if (!server->smbd_conn) {
|
||||
log_rdma_event(ERR, "rdma session already destroyed\n");
|
||||
return -EINVAL;
|
||||
log_rdma_event(INFO, "rdma session already destroyed\n");
|
||||
goto create_conn;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1512,15 +1515,19 @@ int smbd_reconnect(struct TCP_Server_Info *server)
|
|||
}
|
||||
|
||||
/* wait until the transport is destroyed */
|
||||
wait_event(server->smbd_conn->wait_destroy,
|
||||
server->smbd_conn->transport_status == SMBD_DESTROYED);
|
||||
if (!wait_event_timeout(server->smbd_conn->wait_destroy,
|
||||
server->smbd_conn->transport_status == SMBD_DESTROYED, 5*HZ))
|
||||
return -EAGAIN;
|
||||
|
||||
destroy_workqueue(server->smbd_conn->workqueue);
|
||||
kfree(server->smbd_conn);
|
||||
|
||||
create_conn:
|
||||
log_rdma_event(INFO, "creating rdma session\n");
|
||||
server->smbd_conn = smbd_get_connection(
|
||||
server, (struct sockaddr *) &server->dstaddr);
|
||||
log_rdma_event(INFO, "created rdma session info=%p\n",
|
||||
server->smbd_conn);
|
||||
|
||||
return server->smbd_conn ? 0 : -ENOENT;
|
||||
}
|
||||
|
@ -2295,7 +2302,7 @@ static void smbd_mr_recovery_work(struct work_struct *work)
|
|||
rc = ib_dereg_mr(smbdirect_mr->mr);
|
||||
if (rc) {
|
||||
log_rdma_mr(ERR,
|
||||
"ib_dereg_mr faield rc=%x\n",
|
||||
"ib_dereg_mr failed rc=%x\n",
|
||||
rc);
|
||||
smbd_disconnect_rdma_connection(info);
|
||||
}
|
||||
|
@ -2542,6 +2549,8 @@ struct smbd_mr *smbd_register_mr(
|
|||
if (atomic_dec_and_test(&info->mr_used_count))
|
||||
wake_up(&info->wait_for_mr_cleanup);
|
||||
|
||||
smbd_disconnect_rdma_connection(info);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -121,25 +121,12 @@ int
|
|||
mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len)
|
||||
{
|
||||
int rc;
|
||||
unsigned int size;
|
||||
struct crypto_shash *md4;
|
||||
struct sdesc *sdescmd4;
|
||||
struct crypto_shash *md4 = NULL;
|
||||
struct sdesc *sdescmd4 = NULL;
|
||||
|
||||
md4 = crypto_alloc_shash("md4", 0, 0);
|
||||
if (IS_ERR(md4)) {
|
||||
rc = PTR_ERR(md4);
|
||||
cifs_dbg(VFS, "%s: Crypto md4 allocation error %d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
size = sizeof(struct shash_desc) + crypto_shash_descsize(md4);
|
||||
sdescmd4 = kmalloc(size, GFP_KERNEL);
|
||||
if (!sdescmd4) {
|
||||
rc = -ENOMEM;
|
||||
rc = cifs_alloc_hash("md4", &md4, &sdescmd4);
|
||||
if (rc)
|
||||
goto mdfour_err;
|
||||
}
|
||||
sdescmd4->shash.tfm = md4;
|
||||
sdescmd4->shash.flags = 0x0;
|
||||
|
||||
rc = crypto_shash_init(&sdescmd4->shash);
|
||||
if (rc) {
|
||||
|
@ -156,9 +143,7 @@ mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len)
|
|||
cifs_dbg(VFS, "%s: Could not generate md4 hash\n", __func__);
|
||||
|
||||
mdfour_err:
|
||||
crypto_free_shash(md4);
|
||||
kfree(sdescmd4);
|
||||
|
||||
cifs_free_hash(&md4, &sdescmd4);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "cifsglob.h"
|
||||
#include "cifsproto.h"
|
||||
#include "cifs_debug.h"
|
||||
#include "smb2proto.h"
|
||||
#include "smbdirect.h"
|
||||
|
||||
/* Max number of iovectors we can use off the stack when sending requests. */
|
||||
|
@ -751,6 +752,12 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (ses->status == CifsNew)
|
||||
smb311_update_preauth_hash(ses, rqst->rq_iov+1,
|
||||
rqst->rq_nvec-1);
|
||||
#endif
|
||||
|
||||
if (timeout == CIFS_ASYNC_OP)
|
||||
goto out;
|
||||
|
||||
|
@ -783,12 +790,23 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
|
||||
buf = (char *)midQ->resp_buf;
|
||||
resp_iov->iov_base = buf;
|
||||
resp_iov->iov_len = get_rfc1002_length(buf) + 4;
|
||||
resp_iov->iov_len = get_rfc1002_length(buf) +
|
||||
ses->server->vals->header_preamble_size;
|
||||
if (midQ->large_buf)
|
||||
*resp_buf_type = CIFS_LARGE_BUFFER;
|
||||
else
|
||||
*resp_buf_type = CIFS_SMALL_BUFFER;
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (ses->status == CifsNew) {
|
||||
struct kvec iov = {
|
||||
.iov_base = buf + 4,
|
||||
.iov_len = get_rfc1002_length(buf)
|
||||
};
|
||||
smb311_update_preauth_hash(ses, &iov, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
credits = ses->server->ops->get_credits(midQ);
|
||||
|
||||
rc = ses->server->ops->check_receive(midQ, ses->server,
|
||||
|
|
Loading…
Reference in New Issue
Block a user