Skip to content

Commit

Permalink
Merge tag '4.17-rc1SMB3-Fixes' of git://git.samba.org/sfrench/cifs-2.6
Browse files Browse the repository at this point in the history
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
  • Loading branch information
torvalds committed Apr 16, 2018
2 parents f0d98d8 + c1596ff commit 09c9b0e
Show file tree
Hide file tree
Showing 13 changed files with 240 additions and 71 deletions.
17 changes: 0 additions & 17 deletions fs/cifs/cifs_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
34 changes: 22 additions & 12 deletions fs/cifs/cifs_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,26 +39,36 @@ extern int cifsFYI;
#else
#define NOISY 0
#endif
#define ONCE 8

/*
* debug ON
* --------
*/
#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)

/*
Expand Down
4 changes: 4 additions & 0 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down
11 changes: 7 additions & 4 deletions fs/cifs/cifssmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -1416,8 +1418,9 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
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;
Expand Down Expand Up @@ -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;

Expand Down
4 changes: 3 additions & 1 deletion fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) -
Expand Down Expand Up @@ -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]))
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -710,7 +710,7 @@ cifs_get_file_info(struct file *filp)
/* 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)
Expand Down
42 changes: 42 additions & 0 deletions fs/cifs/smb2misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down
18 changes: 10 additions & 8 deletions fs/cifs/smb2ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
}
Expand Down
Loading

0 comments on commit 09c9b0e

Please sign in to comment.