Commit 90c8ce31 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '6.3-rc3-ksmbd-smb3-server-fixes' of git://git.samba.org/ksmbd

Pull ksmbd server fixes from Steve French:

 - return less confusing messages on unsupported dialects
   (STATUS_NOT_SUPPORTED instead of I/O error)

 - fix for overly frequent inactive session termination

 - fix refcount leak

 - fix bounds check problems found by static checkers

 - fix to advertise named stream support correctly

 - Fix AES256 signing bug when connected to from MacOS

* tag '6.3-rc3-ksmbd-smb3-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: return unsupported error on smb1 mount
  ksmbd: return STATUS_NOT_SUPPORTED on unsupported smb2.0 dialect
  ksmbd: don't terminate inactive sessions after a few seconds
  ksmbd: fix possible refcount leak in smb2_open()
  ksmbd: add low bound validation to FSCTL_QUERY_ALLOCATED_RANGES
  ksmbd: add low bound validation to FSCTL_SET_ZERO_DATA
  ksmbd: set FILE_NAMED_STREAMS attribute in FS_ATTRIBUTE_INFORMATION
  ksmbd: fix wrong signingkey creation when encryption is AES256
parents e76db6e5 39b291b8
...@@ -727,8 +727,9 @@ static int generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess, ...@@ -727,8 +727,9 @@ static int generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess,
goto smb3signkey_ret; goto smb3signkey_ret;
} }
if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || if (key_size == SMB3_ENC_DEC_KEY_SIZE &&
conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L256, 4); rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L256, 4);
else else
rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L128, 4); rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L128, 4);
......
...@@ -298,7 +298,7 @@ int ksmbd_conn_handler_loop(void *p) ...@@ -298,7 +298,7 @@ int ksmbd_conn_handler_loop(void *p)
kvfree(conn->request_buf); kvfree(conn->request_buf);
conn->request_buf = NULL; conn->request_buf = NULL;
size = t->ops->read(t, hdr_buf, sizeof(hdr_buf)); size = t->ops->read(t, hdr_buf, sizeof(hdr_buf), -1);
if (size != sizeof(hdr_buf)) if (size != sizeof(hdr_buf))
break; break;
...@@ -319,13 +319,10 @@ int ksmbd_conn_handler_loop(void *p) ...@@ -319,13 +319,10 @@ int ksmbd_conn_handler_loop(void *p)
} }
/* /*
* Check if pdu size is valid (min : smb header size, * Check maximum pdu size(0x00FFFFFF).
* max : 0x00FFFFFF).
*/ */
if (pdu_size < __SMB2_HEADER_STRUCTURE_SIZE || if (pdu_size > MAX_STREAM_PROT_LEN)
pdu_size > MAX_STREAM_PROT_LEN) {
break; break;
}
/* 4 for rfc1002 length field */ /* 4 for rfc1002 length field */
size = pdu_size + 4; size = pdu_size + 4;
...@@ -344,7 +341,7 @@ int ksmbd_conn_handler_loop(void *p) ...@@ -344,7 +341,7 @@ int ksmbd_conn_handler_loop(void *p)
* We already read 4 bytes to find out PDU size, now * We already read 4 bytes to find out PDU size, now
* read in PDU * read in PDU
*/ */
size = t->ops->read(t, conn->request_buf + 4, pdu_size); size = t->ops->read(t, conn->request_buf + 4, pdu_size, 2);
if (size < 0) { if (size < 0) {
pr_err("sock_read failed: %d\n", size); pr_err("sock_read failed: %d\n", size);
break; break;
......
...@@ -114,7 +114,8 @@ struct ksmbd_transport_ops { ...@@ -114,7 +114,8 @@ struct ksmbd_transport_ops {
int (*prepare)(struct ksmbd_transport *t); int (*prepare)(struct ksmbd_transport *t);
void (*disconnect)(struct ksmbd_transport *t); void (*disconnect)(struct ksmbd_transport *t);
void (*shutdown)(struct ksmbd_transport *t); void (*shutdown)(struct ksmbd_transport *t);
int (*read)(struct ksmbd_transport *t, char *buf, unsigned int size); int (*read)(struct ksmbd_transport *t, char *buf,
unsigned int size, int max_retries);
int (*writev)(struct ksmbd_transport *t, struct kvec *iovs, int niov, int (*writev)(struct ksmbd_transport *t, struct kvec *iovs, int niov,
int size, bool need_invalidate_rkey, int size, bool need_invalidate_rkey,
unsigned int remote_key); unsigned int remote_key);
......
...@@ -2977,8 +2977,11 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2977,8 +2977,11 @@ int smb2_open(struct ksmbd_work *work)
sizeof(struct smb_acl) + sizeof(struct smb_acl) +
sizeof(struct smb_ace) * ace_num * 2, sizeof(struct smb_ace) * ace_num * 2,
GFP_KERNEL); GFP_KERNEL);
if (!pntsd) if (!pntsd) {
posix_acl_release(fattr.cf_acls);
posix_acl_release(fattr.cf_dacls);
goto err_out; goto err_out;
}
rc = build_sec_desc(idmap, rc = build_sec_desc(idmap,
pntsd, NULL, 0, pntsd, NULL, 0,
...@@ -4934,6 +4937,10 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, ...@@ -4934,6 +4937,10 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->Attributes |= cpu_to_le32(server_conf.share_fake_fscaps); info->Attributes |= cpu_to_le32(server_conf.share_fake_fscaps);
if (test_share_config_flag(work->tcon->share_conf,
KSMBD_SHARE_FLAG_STREAMS))
info->Attributes |= cpu_to_le32(FILE_NAMED_STREAMS);
info->MaxPathNameComponentLength = cpu_to_le32(stfs.f_namelen); info->MaxPathNameComponentLength = cpu_to_le32(stfs.f_namelen);
len = smbConvertToUTF16((__le16 *)info->FileSystemName, len = smbConvertToUTF16((__le16 *)info->FileSystemName,
"NTFS", PATH_MAX, conn->local_nls, 0); "NTFS", PATH_MAX, conn->local_nls, 0);
...@@ -7444,13 +7451,16 @@ static int fsctl_query_allocated_ranges(struct ksmbd_work *work, u64 id, ...@@ -7444,13 +7451,16 @@ static int fsctl_query_allocated_ranges(struct ksmbd_work *work, u64 id,
if (in_count == 0) if (in_count == 0)
return -EINVAL; return -EINVAL;
start = le64_to_cpu(qar_req->file_offset);
length = le64_to_cpu(qar_req->length);
if (start < 0 || length < 0)
return -EINVAL;
fp = ksmbd_lookup_fd_fast(work, id); fp = ksmbd_lookup_fd_fast(work, id);
if (!fp) if (!fp)
return -ENOENT; return -ENOENT;
start = le64_to_cpu(qar_req->file_offset);
length = le64_to_cpu(qar_req->length);
ret = ksmbd_vfs_fqar_lseek(fp, start, length, ret = ksmbd_vfs_fqar_lseek(fp, start, length,
qar_rsp, in_count, out_count); qar_rsp, in_count, out_count);
if (ret && ret != -E2BIG) if (ret && ret != -E2BIG)
...@@ -7751,7 +7761,7 @@ int smb2_ioctl(struct ksmbd_work *work) ...@@ -7751,7 +7761,7 @@ int smb2_ioctl(struct ksmbd_work *work)
off = le64_to_cpu(zero_data->FileOffset); off = le64_to_cpu(zero_data->FileOffset);
bfz = le64_to_cpu(zero_data->BeyondFinalZero); bfz = le64_to_cpu(zero_data->BeyondFinalZero);
if (off > bfz) { if (off < 0 || bfz < 0 || off > bfz) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
......
...@@ -434,7 +434,7 @@ int ksmbd_extract_shortname(struct ksmbd_conn *conn, const char *longname, ...@@ -434,7 +434,7 @@ int ksmbd_extract_shortname(struct ksmbd_conn *conn, const char *longname,
static int __smb2_negotiate(struct ksmbd_conn *conn) static int __smb2_negotiate(struct ksmbd_conn *conn)
{ {
return (conn->dialect >= SMB21_PROT_ID && return (conn->dialect >= SMB20_PROT_ID &&
conn->dialect <= SMB311_PROT_ID); conn->dialect <= SMB311_PROT_ID);
} }
...@@ -442,9 +442,26 @@ static int smb_handle_negotiate(struct ksmbd_work *work) ...@@ -442,9 +442,26 @@ static int smb_handle_negotiate(struct ksmbd_work *work)
{ {
struct smb_negotiate_rsp *neg_rsp = work->response_buf; struct smb_negotiate_rsp *neg_rsp = work->response_buf;
ksmbd_debug(SMB, "Unsupported SMB protocol\n"); ksmbd_debug(SMB, "Unsupported SMB1 protocol\n");
neg_rsp->hdr.Status.CifsError = STATUS_INVALID_LOGON_TYPE;
return -EINVAL; /*
* Remove 4 byte direct TCP header, add 2 byte bcc and
* 2 byte DialectIndex.
*/
*(__be32 *)work->response_buf =
cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2 + 2);
neg_rsp->hdr.Status.CifsError = STATUS_SUCCESS;
neg_rsp->hdr.Command = SMB_COM_NEGOTIATE;
*(__le32 *)neg_rsp->hdr.Protocol = SMB1_PROTO_NUMBER;
neg_rsp->hdr.Flags = SMBFLG_RESPONSE;
neg_rsp->hdr.Flags2 = SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS |
SMBFLG2_EXT_SEC | SMBFLG2_IS_LONG_NAME;
neg_rsp->hdr.WordCount = 1;
neg_rsp->DialectIndex = cpu_to_le16(work->conn->dialect);
neg_rsp->ByteCount = 0;
return 0;
} }
int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command) int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command)
...@@ -465,7 +482,7 @@ int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command) ...@@ -465,7 +482,7 @@ int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command)
} }
} }
if (command == SMB2_NEGOTIATE_HE && __smb2_negotiate(conn)) { if (command == SMB2_NEGOTIATE_HE) {
ret = smb2_handle_negotiate(work); ret = smb2_handle_negotiate(work);
init_smb2_neg_rsp(work); init_smb2_neg_rsp(work);
return ret; return ret;
......
...@@ -158,8 +158,15 @@ ...@@ -158,8 +158,15 @@
#define SMB1_PROTO_NUMBER cpu_to_le32(0x424d53ff) #define SMB1_PROTO_NUMBER cpu_to_le32(0x424d53ff)
#define SMB_COM_NEGOTIATE 0x72 #define SMB_COM_NEGOTIATE 0x72
#define SMB1_CLIENT_GUID_SIZE (16) #define SMB1_CLIENT_GUID_SIZE (16)
#define SMBFLG_RESPONSE 0x80 /* this PDU is a response from server */
#define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40)
#define SMBFLG2_EXT_SEC cpu_to_le16(0x800)
#define SMBFLG2_ERR_STATUS cpu_to_le16(0x4000)
#define SMBFLG2_UNICODE cpu_to_le16(0x8000)
struct smb_hdr { struct smb_hdr {
__be32 smb_buf_length; __be32 smb_buf_length;
__u8 Protocol[4]; __u8 Protocol[4];
...@@ -199,28 +206,7 @@ struct smb_negotiate_req { ...@@ -199,28 +206,7 @@ struct smb_negotiate_req {
struct smb_negotiate_rsp { struct smb_negotiate_rsp {
struct smb_hdr hdr; /* wct = 17 */ struct smb_hdr hdr; /* wct = 17 */
__le16 DialectIndex; /* 0xFFFF = no dialect acceptable */ __le16 DialectIndex; /* 0xFFFF = no dialect acceptable */
__u8 SecurityMode;
__le16 MaxMpxCount;
__le16 MaxNumberVcs;
__le32 MaxBufferSize;
__le32 MaxRawSize;
__le32 SessionKey;
__le32 Capabilities; /* see below */
__le32 SystemTimeLow;
__le32 SystemTimeHigh;
__le16 ServerTimeZone;
__u8 EncryptionKeyLength;
__le16 ByteCount; __le16 ByteCount;
union {
unsigned char EncryptionKey[8]; /* cap extended security off */
/* followed by Domain name - if extended security is off */
/* followed by 16 bytes of server GUID */
/* then security blob if cap_extended_security negotiated */
struct {
unsigned char GUID[SMB1_CLIENT_GUID_SIZE];
unsigned char SecurityBlob[1];
} __packed extended_response;
} __packed u;
} __packed; } __packed;
struct filesystem_attribute_info { struct filesystem_attribute_info {
......
...@@ -670,7 +670,7 @@ static int smb_direct_post_recv(struct smb_direct_transport *t, ...@@ -670,7 +670,7 @@ static int smb_direct_post_recv(struct smb_direct_transport *t,
} }
static int smb_direct_read(struct ksmbd_transport *t, char *buf, static int smb_direct_read(struct ksmbd_transport *t, char *buf,
unsigned int size) unsigned int size, int unused)
{ {
struct smb_direct_recvmsg *recvmsg; struct smb_direct_recvmsg *recvmsg;
struct smb_direct_data_transfer *data_transfer; struct smb_direct_data_transfer *data_transfer;
......
...@@ -291,16 +291,18 @@ static int ksmbd_tcp_run_kthread(struct interface *iface) ...@@ -291,16 +291,18 @@ static int ksmbd_tcp_run_kthread(struct interface *iface)
/** /**
* ksmbd_tcp_readv() - read data from socket in given iovec * ksmbd_tcp_readv() - read data from socket in given iovec
* @t: TCP transport instance * @t: TCP transport instance
* @iov_orig: base IO vector * @iov_orig: base IO vector
* @nr_segs: number of segments in base iov * @nr_segs: number of segments in base iov
* @to_read: number of bytes to read from socket * @to_read: number of bytes to read from socket
* @max_retries: maximum retry count
* *
* Return: on success return number of bytes read from socket, * Return: on success return number of bytes read from socket,
* otherwise return error number * otherwise return error number
*/ */
static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig, static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig,
unsigned int nr_segs, unsigned int to_read) unsigned int nr_segs, unsigned int to_read,
int max_retries)
{ {
int length = 0; int length = 0;
int total_read; int total_read;
...@@ -308,7 +310,6 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig, ...@@ -308,7 +310,6 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig,
struct msghdr ksmbd_msg; struct msghdr ksmbd_msg;
struct kvec *iov; struct kvec *iov;
struct ksmbd_conn *conn = KSMBD_TRANS(t)->conn; struct ksmbd_conn *conn = KSMBD_TRANS(t)->conn;
int max_retry = 2;
iov = get_conn_iovec(t, nr_segs); iov = get_conn_iovec(t, nr_segs);
if (!iov) if (!iov)
...@@ -335,14 +336,23 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig, ...@@ -335,14 +336,23 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig,
} else if (conn->status == KSMBD_SESS_NEED_RECONNECT) { } else if (conn->status == KSMBD_SESS_NEED_RECONNECT) {
total_read = -EAGAIN; total_read = -EAGAIN;
break; break;
} else if ((length == -ERESTARTSYS || length == -EAGAIN) && } else if (length == -ERESTARTSYS || length == -EAGAIN) {
max_retry) { /*
* If max_retries is negative, Allow unlimited
* retries to keep connection with inactive sessions.
*/
if (max_retries == 0) {
total_read = length;
break;
} else if (max_retries > 0) {
max_retries--;
}
usleep_range(1000, 2000); usleep_range(1000, 2000);
length = 0; length = 0;
max_retry--;
continue; continue;
} else if (length <= 0) { } else if (length <= 0) {
total_read = -EAGAIN; total_read = length;
break; break;
} }
} }
...@@ -358,14 +368,15 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig, ...@@ -358,14 +368,15 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig,
* Return: on success return number of bytes read from socket, * Return: on success return number of bytes read from socket,
* otherwise return error number * otherwise return error number
*/ */
static int ksmbd_tcp_read(struct ksmbd_transport *t, char *buf, unsigned int to_read) static int ksmbd_tcp_read(struct ksmbd_transport *t, char *buf,
unsigned int to_read, int max_retries)
{ {
struct kvec iov; struct kvec iov;
iov.iov_base = buf; iov.iov_base = buf;
iov.iov_len = to_read; iov.iov_len = to_read;
return ksmbd_tcp_readv(TCP_TRANS(t), &iov, 1, to_read); return ksmbd_tcp_readv(TCP_TRANS(t), &iov, 1, to_read, max_retries);
} }
static int ksmbd_tcp_writev(struct ksmbd_transport *t, struct kvec *iov, static int ksmbd_tcp_writev(struct ksmbd_transport *t, struct kvec *iov,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment