Commit 65d7ca59 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '6.4-rc5-smb3-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:
 "Five smb3 server fixes, all also for stable:

   - Fix four slab out of bounds warnings: improve checks for protocol
     id, and for small packet length, and for create context parsing,
     and for negotiate context parsing

   - Fix for incorrect dereferencing POSIX ACLs"

* tag '6.4-rc5-smb3-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: validate smb request protocol id
  ksmbd: check the validation of pdu_size in ksmbd_conn_handler_loop
  ksmbd: fix posix_acls and acls dereferencing possible ERR_PTR()
  ksmbd: fix out-of-bound read in parse_lease_state()
  ksmbd: fix out-of-bound read in deassemble_neg_contexts()
parents 022ce886 1c1bcf2d
...@@ -294,6 +294,9 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn) ...@@ -294,6 +294,9 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
return true; return true;
} }
#define SMB1_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb_hdr))
#define SMB2_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb2_hdr) + 4)
/** /**
* ksmbd_conn_handler_loop() - session thread to listen on new smb requests * ksmbd_conn_handler_loop() - session thread to listen on new smb requests
* @p: connection instance * @p: connection instance
...@@ -350,6 +353,9 @@ int ksmbd_conn_handler_loop(void *p) ...@@ -350,6 +353,9 @@ int ksmbd_conn_handler_loop(void *p)
if (pdu_size > MAX_STREAM_PROT_LEN) if (pdu_size > MAX_STREAM_PROT_LEN)
break; break;
if (pdu_size < SMB1_MIN_SUPPORTED_HEADER_SIZE)
break;
/* 4 for rfc1002 length field */ /* 4 for rfc1002 length field */
/* 1 for implied bcc[0] */ /* 1 for implied bcc[0] */
size = pdu_size + 4 + 1; size = pdu_size + 4 + 1;
...@@ -358,8 +364,6 @@ int ksmbd_conn_handler_loop(void *p) ...@@ -358,8 +364,6 @@ int ksmbd_conn_handler_loop(void *p)
break; break;
memcpy(conn->request_buf, hdr_buf, sizeof(hdr_buf)); memcpy(conn->request_buf, hdr_buf, sizeof(hdr_buf));
if (!ksmbd_smb_request(conn))
break;
/* /*
* We already read 4 bytes to find out PDU size, now * We already read 4 bytes to find out PDU size, now
...@@ -377,6 +381,15 @@ int ksmbd_conn_handler_loop(void *p) ...@@ -377,6 +381,15 @@ int ksmbd_conn_handler_loop(void *p)
continue; continue;
} }
if (!ksmbd_smb_request(conn))
break;
if (((struct smb2_hdr *)smb2_get_msg(conn->request_buf))->ProtocolId ==
SMB2_PROTO_NUMBER) {
if (pdu_size < SMB2_MIN_SUPPORTED_HEADER_SIZE)
break;
}
if (!default_conn_ops.process_fn) { if (!default_conn_ops.process_fn) {
pr_err("No connection request callback\n"); pr_err("No connection request callback\n");
break; break;
......
...@@ -1415,32 +1415,18 @@ void create_lease_buf(u8 *rbuf, struct lease *lease) ...@@ -1415,32 +1415,18 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
*/ */
struct lease_ctx_info *parse_lease_state(void *open_req) struct lease_ctx_info *parse_lease_state(void *open_req)
{ {
char *data_offset;
struct create_context *cc; struct create_context *cc;
unsigned int next = 0;
char *name;
bool found = false;
struct smb2_create_req *req = (struct smb2_create_req *)open_req; struct smb2_create_req *req = (struct smb2_create_req *)open_req;
struct lease_ctx_info *lreq = kzalloc(sizeof(struct lease_ctx_info), struct lease_ctx_info *lreq;
GFP_KERNEL);
if (!lreq) cc = smb2_find_context_vals(req, SMB2_CREATE_REQUEST_LEASE, 4);
if (IS_ERR_OR_NULL(cc))
return NULL; return NULL;
data_offset = (char *)req + le32_to_cpu(req->CreateContextsOffset); lreq = kzalloc(sizeof(struct lease_ctx_info), GFP_KERNEL);
cc = (struct create_context *)data_offset; if (!lreq)
do { return NULL;
cc = (struct create_context *)((char *)cc + next);
name = le16_to_cpu(cc->NameOffset) + (char *)cc;
if (le16_to_cpu(cc->NameLength) != 4 ||
strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4)) {
next = le32_to_cpu(cc->Next);
continue;
}
found = true;
break;
} while (next != 0);
if (found) {
if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) { if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
struct create_lease_v2 *lc = (struct create_lease_v2 *)cc; struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
...@@ -1461,10 +1447,6 @@ struct lease_ctx_info *parse_lease_state(void *open_req) ...@@ -1461,10 +1447,6 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
lreq->version = 1; lreq->version = 1;
} }
return lreq; return lreq;
}
kfree(lreq);
return NULL;
} }
/** /**
......
...@@ -963,13 +963,13 @@ static void decode_sign_cap_ctxt(struct ksmbd_conn *conn, ...@@ -963,13 +963,13 @@ static void decode_sign_cap_ctxt(struct ksmbd_conn *conn,
static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn, static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
struct smb2_negotiate_req *req, struct smb2_negotiate_req *req,
int len_of_smb) unsigned int len_of_smb)
{ {
/* +4 is to account for the RFC1001 len field */ /* +4 is to account for the RFC1001 len field */
struct smb2_neg_context *pctx = (struct smb2_neg_context *)req; struct smb2_neg_context *pctx = (struct smb2_neg_context *)req;
int i = 0, len_of_ctxts; int i = 0, len_of_ctxts;
int offset = le32_to_cpu(req->NegotiateContextOffset); unsigned int offset = le32_to_cpu(req->NegotiateContextOffset);
int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount); unsigned int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount);
__le32 status = STATUS_INVALID_PARAMETER; __le32 status = STATUS_INVALID_PARAMETER;
ksmbd_debug(SMB, "decoding %d negotiate contexts\n", neg_ctxt_cnt); ksmbd_debug(SMB, "decoding %d negotiate contexts\n", neg_ctxt_cnt);
...@@ -983,7 +983,7 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn, ...@@ -983,7 +983,7 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
while (i++ < neg_ctxt_cnt) { while (i++ < neg_ctxt_cnt) {
int clen, ctxt_len; int clen, ctxt_len;
if (len_of_ctxts < sizeof(struct smb2_neg_context)) if (len_of_ctxts < (int)sizeof(struct smb2_neg_context))
break; break;
pctx = (struct smb2_neg_context *)((char *)pctx + offset); pctx = (struct smb2_neg_context *)((char *)pctx + offset);
...@@ -1038,9 +1038,8 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn, ...@@ -1038,9 +1038,8 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
} }
/* offsets must be 8 byte aligned */ /* offsets must be 8 byte aligned */
clen = (clen + 7) & ~0x7; offset = (ctxt_len + 7) & ~0x7;
offset = clen + sizeof(struct smb2_neg_context); len_of_ctxts -= offset;
len_of_ctxts -= clen + sizeof(struct smb2_neg_context);
} }
return status; return status;
} }
......
...@@ -158,7 +158,19 @@ int ksmbd_verify_smb_message(struct ksmbd_work *work) ...@@ -158,7 +158,19 @@ int ksmbd_verify_smb_message(struct ksmbd_work *work)
*/ */
bool ksmbd_smb_request(struct ksmbd_conn *conn) bool ksmbd_smb_request(struct ksmbd_conn *conn)
{ {
return conn->request_buf[0] == 0; __le32 *proto = (__le32 *)smb2_get_msg(conn->request_buf);
if (*proto == SMB2_COMPRESSION_TRANSFORM_ID) {
pr_err_ratelimited("smb2 compression not support yet");
return false;
}
if (*proto != SMB1_PROTO_NUMBER &&
*proto != SMB2_PROTO_NUMBER &&
*proto != SMB2_TRANSFORM_PROTO_NUM)
return false;
return true;
} }
static bool supported_protocol(int idx) static bool supported_protocol(int idx)
......
...@@ -1290,7 +1290,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, ...@@ -1290,7 +1290,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) { if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
posix_acls = get_inode_acl(d_inode(path->dentry), ACL_TYPE_ACCESS); posix_acls = get_inode_acl(d_inode(path->dentry), ACL_TYPE_ACCESS);
if (posix_acls && !found) { if (!IS_ERR_OR_NULL(posix_acls) && !found) {
unsigned int id = -1; unsigned int id = -1;
pa_entry = posix_acls->a_entries; pa_entry = posix_acls->a_entries;
...@@ -1314,7 +1314,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, ...@@ -1314,7 +1314,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
} }
} }
} }
if (posix_acls) if (!IS_ERR_OR_NULL(posix_acls))
posix_acl_release(posix_acls); posix_acl_release(posix_acls);
} }
......
...@@ -1321,7 +1321,7 @@ static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct mnt_idmap *id ...@@ -1321,7 +1321,7 @@ static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct mnt_idmap *id
return NULL; return NULL;
posix_acls = get_inode_acl(inode, acl_type); posix_acls = get_inode_acl(inode, acl_type);
if (!posix_acls) if (IS_ERR_OR_NULL(posix_acls))
return NULL; return NULL;
smb_acl = kzalloc(sizeof(struct xattr_smb_acl) + smb_acl = kzalloc(sizeof(struct xattr_smb_acl) +
...@@ -1830,7 +1830,7 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap, ...@@ -1830,7 +1830,7 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
return -EOPNOTSUPP; return -EOPNOTSUPP;
acls = get_inode_acl(parent_inode, ACL_TYPE_DEFAULT); acls = get_inode_acl(parent_inode, ACL_TYPE_DEFAULT);
if (!acls) if (IS_ERR_OR_NULL(acls))
return -ENOENT; return -ENOENT;
pace = acls->a_entries; pace = acls->a_entries;
......
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