SMB3 fixes, a few for stable, and some important cleanup work from Ronnie of the smb3 transport code
-----BEGIN PGP SIGNATURE----- iQGwBAABCAAaBQJa0mDhExxzbWZyZW5jaEBnbWFpbC5jb20ACgkQiiy9cAdyT1HA EQv+KxZAFONG/YGBIdoyJevnSobzZSTYgsrEmox28rIvWSFr6Xkt9K6WN4lki+Td nacByZBhyeKPp7CxdgjmiNunbGfBZJsWk5LwtgdE2jOLjM9CFq8Z7m2qmkXQ4IkJ EoH+NWpCUvEe9nj8oaTdSelR2OHH63SG5E5dK29eOB59ixcVe7qKUG29SpJks9qd mCdZyhYyuzh469CKGFeQ8qfWopBH+QFBs4SrpQ9d4liNtZ3W8zTsQ3ezX069AGlU Ef2xVTT1DtlZ4/6SiXBKlXGH3jjUg67vEGHzT3ZJwfLVNhTLEpKM/hsPiduSnjS8 JqdVRdFLc2lQzr4HknhNR9yuE5wT5tZM4iZOjNDwT6Sef2Mt0QIBuYI6kb4mv6Qg aCVv7uXUMdvSrTk0mYiO1dXYozGUC+uFhJCuaiLax583o3ihp+/INDosQyqTbavZ amRBZpWeNysSJwwJu21RdJiM74+fasR/CDy11U94ssxplg1qE72M8DShK7kXtUIy g9ZW =Ah5z -----END PGP SIGNATURE----- Merge tag '4.17-rc1SMB3-Fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull cifs fixes from Steve French: "SMB3 fixes, a few for stable, and some important cleanup work from Ronnie of the smb3 transport code" * tag '4.17-rc1SMB3-Fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: change validate_buf to validate_iov cifs: remove rfc1002 hardcoded constants from cifs_discard_remaining_data() cifs: Change SMB2_open to return an iov for the error parameter cifs: add resp_buf_size to the mid_q_entry structure smb3.11: replace a 4 with server->vals->header_preamble_size cifs: replace a 4 with server->vals->header_preamble_size cifs: add pdu_size to the TCP_Server_Info structure SMB311: Improve checking of negotiate security contexts SMB3: Fix length checking of SMB3.11 negotiate request CIFS: add ONCE flag for cifs_dbg type cifs: Use ULL suffix for 64-bit constant SMB3: Log at least once if tree connect fails during reconnect cifs: smb2pdu: Fix potential NULL pointer dereference
This commit is contained in:
commit
09c9b0eaa0
@ -42,23 +42,6 @@ cifs_dump_mem(char *label, void *data, int length)
|
||||
data, length, true);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG
|
||||
void cifs_vfs_err(const char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
|
||||
pr_err_ratelimited("CIFS VFS: %pV", &vaf);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
void cifs_dump_detail(void *buf)
|
||||
{
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
|
@ -39,6 +39,7 @@ extern int cifsFYI;
|
||||
#else
|
||||
#define NOISY 0
|
||||
#endif
|
||||
#define ONCE 8
|
||||
|
||||
/*
|
||||
* debug ON
|
||||
@ -46,19 +47,28 @@ extern int cifsFYI;
|
||||
*/
|
||||
#ifdef CONFIG_CIFS_DEBUG
|
||||
|
||||
__printf(1, 2) void cifs_vfs_err(const char *fmt, ...);
|
||||
|
||||
/* information message: e.g., configuration, major event */
|
||||
#define cifs_dbg(type, fmt, ...) \
|
||||
do { \
|
||||
if (type == FYI && cifsFYI & CIFS_INFO) { \
|
||||
pr_debug_ratelimited("%s: " \
|
||||
fmt, __FILE__, ##__VA_ARGS__); \
|
||||
} else if (type == VFS) { \
|
||||
cifs_vfs_err(fmt, ##__VA_ARGS__); \
|
||||
} else if (type == NOISY && type != 0) { \
|
||||
pr_debug_ratelimited(fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
#define cifs_dbg_func(ratefunc, type, fmt, ...) \
|
||||
do { \
|
||||
if ((type) & FYI && cifsFYI & CIFS_INFO) { \
|
||||
pr_debug_ ## ratefunc("%s: " \
|
||||
fmt, __FILE__, ##__VA_ARGS__); \
|
||||
} else if ((type) & VFS) { \
|
||||
pr_err_ ## ratefunc("CuIFS VFS: " \
|
||||
fmt, ##__VA_ARGS__); \
|
||||
} else if ((type) & NOISY && (NOISY != 0)) { \
|
||||
pr_debug_ ## ratefunc(fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define cifs_dbg(type, fmt, ...) \
|
||||
do { \
|
||||
if ((type) & ONCE) \
|
||||
cifs_dbg_func(once, \
|
||||
type, fmt, ##__VA_ARGS__); \
|
||||
else \
|
||||
cifs_dbg_func(ratelimited, \
|
||||
type, fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
|
@ -665,6 +665,8 @@ struct TCP_Server_Info {
|
||||
struct delayed_work echo; /* echo ping workqueue job */
|
||||
char *smallbuf; /* pointer to current "small" buffer */
|
||||
char *bigbuf; /* pointer to current "big" buffer */
|
||||
/* Total size of this PDU. Only valid from cifs_demultiplex_thread */
|
||||
unsigned int pdu_size;
|
||||
unsigned int total_read; /* total amount of data read in this pass */
|
||||
#ifdef CONFIG_CIFS_FSCACHE
|
||||
struct fscache_cookie *fscache; /* client index cache cookie */
|
||||
@ -676,6 +678,7 @@ struct TCP_Server_Info {
|
||||
unsigned int max_read;
|
||||
unsigned int max_write;
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
__le16 cipher_type;
|
||||
/* save initital negprot hash */
|
||||
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
|
||||
#endif /* 3.1.1 */
|
||||
@ -1373,6 +1376,7 @@ struct mid_q_entry {
|
||||
mid_handle_t *handle; /* call handle mid callback */
|
||||
void *callback_data; /* general purpose pointer for callback */
|
||||
void *resp_buf; /* pointer to received SMB header */
|
||||
unsigned int resp_buf_size;
|
||||
int mid_state; /* wish this were enum but can not pass to wait_event */
|
||||
unsigned int mid_flags;
|
||||
__le16 command; /* smb command code */
|
||||
|
@ -206,8 +206,10 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
|
||||
|
||||
if (rc)
|
||||
if (rc) {
|
||||
printk_once(KERN_WARNING "reconnect tcon failed rc = %d\n", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
atomic_inc(&tconInfoReconnectCount);
|
||||
|
||||
@ -1416,8 +1418,9 @@ openRetry:
|
||||
int
|
||||
cifs_discard_remaining_data(struct TCP_Server_Info *server)
|
||||
{
|
||||
unsigned int rfclen = get_rfc1002_length(server->smallbuf);
|
||||
int remaining = rfclen + 4 - server->total_read;
|
||||
unsigned int rfclen = server->pdu_size;
|
||||
int remaining = rfclen + server->vals->header_preamble_size -
|
||||
server->total_read;
|
||||
|
||||
while (remaining > 0) {
|
||||
int length;
|
||||
@ -1454,7 +1457,7 @@ 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) +
|
||||
unsigned int buflen = server->pdu_size +
|
||||
server->vals->header_preamble_size;
|
||||
bool use_rdma_mr = false;
|
||||
|
||||
|
@ -772,7 +772,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
{
|
||||
int length;
|
||||
char *buf = server->smallbuf;
|
||||
unsigned int pdu_length = get_rfc1002_length(buf);
|
||||
unsigned int pdu_length = server->pdu_size;
|
||||
|
||||
/* make sure this will fit in a large buffer */
|
||||
if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
|
||||
@ -881,6 +881,7 @@ cifs_demultiplex_thread(void *p)
|
||||
* so we can now interpret the length field.
|
||||
*/
|
||||
pdu_length = get_rfc1002_length(buf);
|
||||
server->pdu_size = pdu_length;
|
||||
|
||||
cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length);
|
||||
if (!is_smb_response(server, buf[0]))
|
||||
@ -927,6 +928,7 @@ cifs_demultiplex_thread(void *p)
|
||||
|
||||
server->lstrp = jiffies;
|
||||
if (mid_entry != NULL) {
|
||||
mid_entry->resp_buf_size = server->pdu_size;
|
||||
if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) &&
|
||||
mid_entry->mid_state == MID_RESPONSE_RECEIVED &&
|
||||
server->ops->handle_cancelled_mid)
|
||||
|
@ -710,7 +710,7 @@ cgfi_exit:
|
||||
/* 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 */
|
||||
const __u64 hash_mult = 1125899906842597ULL; /* a big enough prime */
|
||||
__u64 hash = 0;
|
||||
|
||||
while (*str)
|
||||
|
@ -93,6 +93,43 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
|
||||
/* SMB2_OPLOCK_BREAK */ cpu_to_le16(24)
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
static __u32 get_neg_ctxt_len(struct smb2_hdr *hdr, __u32 len, __u32 non_ctxlen,
|
||||
size_t hdr_preamble_size)
|
||||
{
|
||||
__u16 neg_count;
|
||||
__u32 nc_offset, size_of_pad_before_neg_ctxts;
|
||||
struct smb2_negotiate_rsp *pneg_rsp = (struct smb2_negotiate_rsp *)hdr;
|
||||
|
||||
/* Negotiate contexts are only valid for latest dialect SMB3.11 */
|
||||
neg_count = le16_to_cpu(pneg_rsp->NegotiateContextCount);
|
||||
if ((neg_count == 0) ||
|
||||
(pneg_rsp->DialectRevision != cpu_to_le16(SMB311_PROT_ID)))
|
||||
return 0;
|
||||
|
||||
/* Make sure that negotiate contexts start after gss security blob */
|
||||
nc_offset = le32_to_cpu(pneg_rsp->NegotiateContextOffset);
|
||||
if (nc_offset < non_ctxlen - hdr_preamble_size /* RFC1001 len */) {
|
||||
printk_once(KERN_WARNING "invalid negotiate context offset\n");
|
||||
return 0;
|
||||
}
|
||||
size_of_pad_before_neg_ctxts = nc_offset -
|
||||
(non_ctxlen - hdr_preamble_size);
|
||||
|
||||
/* Verify that at least minimal negotiate contexts fit within frame */
|
||||
if (len < nc_offset + (neg_count * sizeof(struct smb2_neg_context))) {
|
||||
printk_once(KERN_WARNING "negotiate context goes beyond end\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cifs_dbg(FYI, "length of negcontexts %d pad %d\n",
|
||||
len - nc_offset, size_of_pad_before_neg_ctxts);
|
||||
|
||||
/* length of negcontexts including pad from end of sec blob to them */
|
||||
return (len - nc_offset) + size_of_pad_before_neg_ctxts;
|
||||
}
|
||||
#endif /* CIFS_SMB311 */
|
||||
|
||||
int
|
||||
smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
|
||||
{
|
||||
@ -198,6 +235,11 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
|
||||
|
||||
clc_len = smb2_calc_size(hdr);
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (shdr->Command == SMB2_NEGOTIATE)
|
||||
clc_len += get_neg_ctxt_len(hdr, len, clc_len,
|
||||
srvr->vals->header_preamble_size);
|
||||
#endif /* SMB311 */
|
||||
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);
|
||||
|
@ -1451,6 +1451,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
struct kvec err_iov = {NULL, 0};
|
||||
struct smb2_err_rsp *err_buf = NULL;
|
||||
struct smb2_symlink_err_rsp *symlink;
|
||||
unsigned int sub_len;
|
||||
@ -1473,15 +1474,16 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, &err_buf);
|
||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, &err_iov);
|
||||
|
||||
if (!rc || !err_buf) {
|
||||
kfree(utf16_path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
err_buf = err_iov.iov_base;
|
||||
if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) ||
|
||||
get_rfc1002_length(err_buf) + server->vals->header_preamble_size < SMB2_SYMLINK_STRUCT_SIZE) {
|
||||
err_iov.iov_len + server->vals->header_preamble_size < SMB2_SYMLINK_STRUCT_SIZE) {
|
||||
kfree(utf16_path);
|
||||
return -ENOENT;
|
||||
}
|
||||
@ -1494,13 +1496,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) + server->vals->header_preamble_size <
|
||||
if (err_iov.iov_len + server->vals->header_preamble_size <
|
||||
SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {
|
||||
kfree(utf16_path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (get_rfc1002_length(err_buf) + server->vals->header_preamble_size <
|
||||
if (err_iov.iov_len + server->vals->header_preamble_size <
|
||||
SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) {
|
||||
kfree(utf16_path);
|
||||
return -ENOENT;
|
||||
@ -2550,7 +2552,7 @@ 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) + server->vals->header_preamble_size;
|
||||
unsigned int buflen = server->pdu_size + server->vals->header_preamble_size;
|
||||
int rc;
|
||||
int i = 0;
|
||||
|
||||
@ -2624,7 +2626,7 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
|
||||
{
|
||||
int length;
|
||||
char *buf = server->smallbuf;
|
||||
unsigned int pdu_length = get_rfc1002_length(buf);
|
||||
unsigned int pdu_length = server->pdu_size;
|
||||
unsigned int buf_size;
|
||||
struct mid_q_entry *mid_entry;
|
||||
|
||||
@ -2668,7 +2670,7 @@ static int
|
||||
smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
||||
{
|
||||
char *buf = server->smallbuf;
|
||||
unsigned int pdu_length = get_rfc1002_length(buf);
|
||||
unsigned int pdu_length = server->pdu_size;
|
||||
struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
|
||||
unsigned int orig_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
|
||||
|
||||
@ -2699,7 +2701,7 @@ 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) +
|
||||
return handle_read_data(server, mid, buf, server->pdu_size +
|
||||
server->vals->header_preamble_size,
|
||||
NULL, 0, 0);
|
||||
}
|
||||
|
@ -268,8 +268,11 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
|
||||
mutex_unlock(&tcon->ses->session_mutex);
|
||||
|
||||
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
/* If sess reconnected but tcon didn't, something strange ... */
|
||||
printk_once(KERN_WARNING "reconnect tcon failed rc = %d\n", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (smb2_command != SMB2_INTERNAL_CMD)
|
||||
queue_delayed_work(cifsiod_wq, &server->reconnect, 0);
|
||||
@ -403,6 +406,100 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
|
||||
*total_len += 4 + sizeof(struct smb2_preauth_neg_context)
|
||||
+ sizeof(struct smb2_encryption_neg_context);
|
||||
}
|
||||
|
||||
static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
|
||||
{
|
||||
unsigned int len = le16_to_cpu(ctxt->DataLength);
|
||||
|
||||
/* If invalid preauth context warn but use what we requested, SHA-512 */
|
||||
if (len < MIN_PREAUTH_CTXT_DATA_LEN) {
|
||||
printk_once(KERN_WARNING "server sent bad preauth context\n");
|
||||
return;
|
||||
}
|
||||
if (le16_to_cpu(ctxt->HashAlgorithmCount) != 1)
|
||||
printk_once(KERN_WARNING "illegal SMB3 hash algorithm count\n");
|
||||
if (ctxt->HashAlgorithms != SMB2_PREAUTH_INTEGRITY_SHA512)
|
||||
printk_once(KERN_WARNING "unknown SMB3 hash algorithm\n");
|
||||
}
|
||||
|
||||
static int decode_encrypt_ctx(struct TCP_Server_Info *server,
|
||||
struct smb2_encryption_neg_context *ctxt)
|
||||
{
|
||||
unsigned int len = le16_to_cpu(ctxt->DataLength);
|
||||
|
||||
cifs_dbg(FYI, "decode SMB3.11 encryption neg context of len %d\n", len);
|
||||
if (len < MIN_ENCRYPT_CTXT_DATA_LEN) {
|
||||
printk_once(KERN_WARNING "server sent bad crypto ctxt len\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(ctxt->CipherCount) != 1) {
|
||||
printk_once(KERN_WARNING "illegal SMB3.11 cipher count\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
cifs_dbg(FYI, "SMB311 cipher type:%d\n", le16_to_cpu(ctxt->Ciphers[0]));
|
||||
if ((ctxt->Ciphers[0] != SMB2_ENCRYPTION_AES128_CCM) &&
|
||||
(ctxt->Ciphers[0] != SMB2_ENCRYPTION_AES128_GCM)) {
|
||||
printk_once(KERN_WARNING "invalid SMB3.11 cipher returned\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
server->cipher_type = ctxt->Ciphers[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
|
||||
struct TCP_Server_Info *server)
|
||||
{
|
||||
struct smb2_neg_context *pctx;
|
||||
unsigned int offset = le32_to_cpu(rsp->NegotiateContextOffset);
|
||||
unsigned int ctxt_cnt = le16_to_cpu(rsp->NegotiateContextCount);
|
||||
unsigned int len_of_smb = be32_to_cpu(rsp->hdr.smb2_buf_length);
|
||||
unsigned int len_of_ctxts, i;
|
||||
int rc = 0;
|
||||
|
||||
cifs_dbg(FYI, "decoding %d negotiate contexts\n", ctxt_cnt);
|
||||
if (len_of_smb <= offset) {
|
||||
cifs_dbg(VFS, "Invalid response: negotiate context offset\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len_of_ctxts = len_of_smb - offset;
|
||||
|
||||
for (i = 0; i < ctxt_cnt; i++) {
|
||||
int clen;
|
||||
/* check that offset is not beyond end of SMB */
|
||||
if (len_of_ctxts == 0)
|
||||
break;
|
||||
|
||||
if (len_of_ctxts < sizeof(struct smb2_neg_context))
|
||||
break;
|
||||
|
||||
pctx = (struct smb2_neg_context *)(offset +
|
||||
server->vals->header_preamble_size + (char *)rsp);
|
||||
clen = le16_to_cpu(pctx->DataLength);
|
||||
if (clen > len_of_ctxts)
|
||||
break;
|
||||
|
||||
if (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES)
|
||||
decode_preauth_context(
|
||||
(struct smb2_preauth_neg_context *)pctx);
|
||||
else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES)
|
||||
rc = decode_encrypt_ctx(server,
|
||||
(struct smb2_encryption_neg_context *)pctx);
|
||||
else
|
||||
cifs_dbg(VFS, "unknown negcontext of type %d ignored\n",
|
||||
le16_to_cpu(pctx->ContextType));
|
||||
|
||||
if (rc)
|
||||
break;
|
||||
/* offsets must be 8 byte aligned */
|
||||
clen = (clen + 7) & ~0x7;
|
||||
offset += clen + sizeof(struct smb2_neg_context);
|
||||
len_of_ctxts -= clen;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#else
|
||||
static void assemble_neg_contexts(struct smb2_negotiate_req *req,
|
||||
unsigned int *total_len)
|
||||
@ -616,6 +713,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
||||
else if (rc == 0)
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
|
||||
if (rsp->NegotiateContextCount)
|
||||
rc = smb311_decode_neg_context(rsp, server);
|
||||
else
|
||||
cifs_dbg(VFS, "Missing expected negotiate contexts\n");
|
||||
}
|
||||
#endif /* CONFIG_CIFS_SMB311 */
|
||||
neg_exit:
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
return rc;
|
||||
@ -1026,7 +1132,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (offsetof(struct smb2_sess_setup_rsp, Buffer) - 4 !=
|
||||
if (offsetof(struct smb2_sess_setup_rsp, Buffer) - ses->server->vals->header_preamble_size !=
|
||||
le16_to_cpu(rsp->SecurityBufferOffset)) {
|
||||
cifs_dbg(VFS, "Invalid security buffer offset %d\n",
|
||||
le16_to_cpu(rsp->SecurityBufferOffset));
|
||||
@ -1701,7 +1807,7 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
|
||||
int
|
||||
SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
||||
__u8 *oplock, struct smb2_file_all_info *buf,
|
||||
struct smb2_err_rsp **err_buf)
|
||||
struct kvec *err_iov)
|
||||
{
|
||||
struct smb2_create_req *req;
|
||||
struct smb2_create_rsp *rsp;
|
||||
@ -1841,9 +1947,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
||||
|
||||
if (rc != 0) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_CREATE_HE);
|
||||
if (err_buf && rsp)
|
||||
*err_buf = kmemdup(rsp, get_rfc1002_length(rsp) + 4,
|
||||
GFP_KERNEL);
|
||||
if (err_iov && rsp) {
|
||||
*err_iov = rsp_iov;
|
||||
resp_buftype = CIFS_NO_BUFFER;
|
||||
rsp = NULL;
|
||||
}
|
||||
goto creat_exit;
|
||||
}
|
||||
|
||||
@ -2098,13 +2206,13 @@ close_exit:
|
||||
}
|
||||
|
||||
static int
|
||||
validate_buf(unsigned int offset, unsigned int buffer_length,
|
||||
struct smb2_hdr *hdr, unsigned int min_buf_size)
|
||||
|
||||
validate_iov(struct TCP_Server_Info *server,
|
||||
unsigned int offset, unsigned int buffer_length,
|
||||
struct kvec *iov, unsigned int min_buf_size)
|
||||
{
|
||||
unsigned int smb_len = be32_to_cpu(hdr->smb2_buf_length);
|
||||
char *end_of_smb = smb_len + 4 /* RFC1001 length field */ + (char *)hdr;
|
||||
char *begin_of_buf = 4 /* RFC1001 len field */ + offset + (char *)hdr;
|
||||
unsigned int smb_len = iov->iov_len;
|
||||
char *end_of_smb = smb_len + server->vals->header_preamble_size + (char *)iov->iov_base;
|
||||
char *begin_of_buf = server->vals->header_preamble_size + offset + (char *)iov->iov_base;
|
||||
char *end_of_buf = begin_of_buf + buffer_length;
|
||||
|
||||
|
||||
@ -2134,18 +2242,18 @@ validate_buf(unsigned int offset, unsigned int buffer_length,
|
||||
* Caller must free buffer.
|
||||
*/
|
||||
static int
|
||||
validate_and_copy_buf(unsigned int offset, unsigned int buffer_length,
|
||||
struct smb2_hdr *hdr, unsigned int minbufsize,
|
||||
validate_and_copy_iov(struct TCP_Server_Info *server,
|
||||
unsigned int offset, unsigned int buffer_length,
|
||||
struct kvec *iov, unsigned int minbufsize,
|
||||
char *data)
|
||||
|
||||
{
|
||||
char *begin_of_buf = 4 /* RFC1001 len field */ + offset + (char *)hdr;
|
||||
char *begin_of_buf = server->vals->header_preamble_size + offset + (char *)(iov->iov_base);
|
||||
int rc;
|
||||
|
||||
if (!data)
|
||||
return -EINVAL;
|
||||
|
||||
rc = validate_buf(offset, buffer_length, hdr, minbufsize);
|
||||
rc = validate_iov(server, offset, buffer_length, iov, minbufsize);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@ -2223,9 +2331,10 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
}
|
||||
}
|
||||
|
||||
rc = validate_and_copy_buf(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
rc = validate_and_copy_iov(ses->server,
|
||||
le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength),
|
||||
&rsp->hdr, min_len, *data);
|
||||
&rsp_iov, min_len, *data);
|
||||
|
||||
qinf_exit:
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
@ -3146,8 +3255,9 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
goto qdir_exit;
|
||||
}
|
||||
|
||||
rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr,
|
||||
rc = validate_iov(server,
|
||||
le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength), &rsp_iov,
|
||||
info_buf_size);
|
||||
if (rc)
|
||||
goto qdir_exit;
|
||||
@ -3454,7 +3564,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;
|
||||
struct TCP_Server_Info *server;
|
||||
int rc;
|
||||
struct smb2_query_info_req *req;
|
||||
unsigned int total_len;
|
||||
@ -3464,6 +3574,8 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
|
||||
if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
|
||||
return -EIO;
|
||||
|
||||
server = tcon->ses->server;
|
||||
|
||||
rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req,
|
||||
&total_len);
|
||||
if (rc)
|
||||
@ -3517,8 +3629,9 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
||||
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,
|
||||
rc = validate_iov(server,
|
||||
le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength), &rsp_iov,
|
||||
sizeof(struct smb2_fs_full_size_info));
|
||||
if (!rc)
|
||||
copy_fs_info_to_kstatfs(info, fsdata);
|
||||
@ -3574,7 +3687,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
||||
rsp_len = le32_to_cpu(rsp->OutputBufferLength);
|
||||
offset = le16_to_cpu(rsp->OutputBufferOffset);
|
||||
rc = validate_buf(offset, rsp_len, &rsp->hdr, min_len);
|
||||
rc = validate_iov(server, offset, rsp_len, &rsp_iov, min_len);
|
||||
if (rc)
|
||||
goto qfsattr_exit;
|
||||
|
||||
|
@ -263,11 +263,19 @@ struct smb2_negotiate_req {
|
||||
#define SMB2_NT_FIND 0x00100000
|
||||
#define SMB2_LARGE_FILES 0x00200000
|
||||
|
||||
struct smb2_neg_context {
|
||||
__le16 ContextType;
|
||||
__le16 DataLength;
|
||||
__le32 Reserved;
|
||||
/* Followed by array of data */
|
||||
} __packed;
|
||||
|
||||
#define SMB311_SALT_SIZE 32
|
||||
/* Hash Algorithm Types */
|
||||
#define SMB2_PREAUTH_INTEGRITY_SHA512 cpu_to_le16(0x0001)
|
||||
#define SMB2_PREAUTH_HASH_SIZE 64
|
||||
|
||||
#define MIN_PREAUTH_CTXT_DATA_LEN (SMB311_SALT_SIZE + 6)
|
||||
struct smb2_preauth_neg_context {
|
||||
__le16 ContextType; /* 1 */
|
||||
__le16 DataLength;
|
||||
@ -282,6 +290,8 @@ struct smb2_preauth_neg_context {
|
||||
#define SMB2_ENCRYPTION_AES128_CCM cpu_to_le16(0x0001)
|
||||
#define SMB2_ENCRYPTION_AES128_GCM cpu_to_le16(0x0002)
|
||||
|
||||
/* Min encrypt context data is one cipher so 2 bytes + 2 byte count field */
|
||||
#define MIN_ENCRYPT_CTXT_DATA_LEN 4
|
||||
struct smb2_encryption_neg_context {
|
||||
__le16 ContextType; /* 2 */
|
||||
__le16 DataLength;
|
||||
|
@ -122,7 +122,7 @@ extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);
|
||||
extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms,
|
||||
__le16 *path, __u8 *oplock,
|
||||
struct smb2_file_all_info *buf,
|
||||
struct smb2_err_rsp **err_buf);
|
||||
struct kvec *err_iov);
|
||||
extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, u32 opcode,
|
||||
bool is_fsctl, char *in_data, u32 indatalen,
|
||||
|
@ -604,7 +604,7 @@ int
|
||||
smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
||||
bool log_error)
|
||||
{
|
||||
unsigned int len = get_rfc1002_length(mid->resp_buf);
|
||||
unsigned int len = mid->resp_buf_size;
|
||||
struct kvec iov[2];
|
||||
struct smb_rqst rqst = { .rq_iov = iov,
|
||||
.rq_nvec = 2 };
|
||||
|
@ -790,7 +790,7 @@ 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) +
|
||||
resp_iov->iov_len = midQ->resp_buf_size +
|
||||
ses->server->vals->header_preamble_size;
|
||||
if (midQ->large_buf)
|
||||
*resp_buf_type = CIFS_LARGE_BUFFER;
|
||||
|
Loading…
Reference in New Issue
Block a user