mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-20 07:09:58 +00:00
four ksmbd server fixes, including three for stable
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmQvWyAACgkQiiy9cAdy T1FSnAv/dqpNpgkqeC0qhytnJfcDCzuSDWcMlB7Nuyd3HcLRJAzdIs9T+Zphfrkj sDGbznjAdNt8+vw7uKIl25NEgm2UbX4SiYeaQX5wUqcrnksbzXyBiZG0Y2Hr0SKi MwIq75Lj7vA2wtFuCWM5Q3vTAqSE0RDp+m+LYjb8peLjRw2OJ8siaLdiK1l0e2PD YaWJg04yrzl14Uk8A+Qz/+EsNz0jHt7hQ9HETsNzbRVaIHBYfIpqgGQHILxEdU6a EqzbYAfYdmitGv2guj1iEMsgeJN3P8DQOQ2Nb80IdIcoq/Erq2q++T0O6xdy/84g PdFZD14fsAe7ao5lGc2K5DQPGLSIF7ZNkVaCJEa3chLpXxmnwqt3TLUzbj0jP7Yv huM7dEDpmVUosIahycKcR5vVjwB9lnCy18AIFwHZzdabzZRgNPx8eCAkjc7+HwD0 RZ3zcZpqxY3aEUNbktnp7XNJo9ifo+gIcNQC/yAoINY7IfK3wQWamC3FZpo1fFqU jkUsq3lq =xypJ -----END PGP SIGNATURE----- Merge tag '6.3-rc5-ksmbd-server-fixes' of git://git.samba.org/ksmbd Pull ksmbd server fixes from Steve French: "Four fixes, three for stable: - slab out of bounds fix - lock cancellation fix - minor cleanup to address clang warning - fix for xfstest 551 (wrong parms passed to kvmalloc)" * tag '6.3-rc5-ksmbd-server-fixes' of git://git.samba.org/ksmbd: ksmbd: fix slab-out-of-bounds in init_smb2_rsp_hdr ksmbd: delete asynchronous work from list ksmbd: remove unused is_char_allowed function ksmbd: do not call kvmalloc() with __GFP_NORETRY | __GFP_NO_WARN
This commit is contained in:
commit
a1e6fff395
@ -112,10 +112,8 @@ void ksmbd_conn_enqueue_request(struct ksmbd_work *work)
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
struct list_head *requests_queue = NULL;
|
||||
|
||||
if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE) {
|
||||
if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE)
|
||||
requests_queue = &conn->requests;
|
||||
work->synchronous = true;
|
||||
}
|
||||
|
||||
if (requests_queue) {
|
||||
atomic_inc(&conn->req_running);
|
||||
@ -136,14 +134,14 @@ int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
|
||||
|
||||
if (!work->multiRsp)
|
||||
atomic_dec(&conn->req_running);
|
||||
spin_lock(&conn->request_lock);
|
||||
if (!work->multiRsp) {
|
||||
spin_lock(&conn->request_lock);
|
||||
list_del_init(&work->request_entry);
|
||||
if (!work->synchronous)
|
||||
list_del_init(&work->async_request_entry);
|
||||
spin_unlock(&conn->request_lock);
|
||||
if (work->asynchronous)
|
||||
release_async_work(work);
|
||||
ret = 0;
|
||||
}
|
||||
spin_unlock(&conn->request_lock);
|
||||
|
||||
wake_up_all(&conn->req_running_q);
|
||||
return ret;
|
||||
@ -326,10 +324,7 @@ int ksmbd_conn_handler_loop(void *p)
|
||||
|
||||
/* 4 for rfc1002 length field */
|
||||
size = pdu_size + 4;
|
||||
conn->request_buf = kvmalloc(size,
|
||||
GFP_KERNEL |
|
||||
__GFP_NOWARN |
|
||||
__GFP_NORETRY);
|
||||
conn->request_buf = kvmalloc(size, GFP_KERNEL);
|
||||
if (!conn->request_buf)
|
||||
break;
|
||||
|
||||
|
@ -68,7 +68,7 @@ struct ksmbd_work {
|
||||
/* Request is encrypted */
|
||||
bool encrypted:1;
|
||||
/* Is this SYNC or ASYNC ksmbd_work */
|
||||
bool synchronous:1;
|
||||
bool asynchronous:1;
|
||||
bool need_invalidate_rkey:1;
|
||||
|
||||
unsigned int remote_key;
|
||||
|
@ -289,10 +289,7 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
|
||||
work->request_buf = conn->request_buf;
|
||||
conn->request_buf = NULL;
|
||||
|
||||
if (ksmbd_init_smb_server(work)) {
|
||||
ksmbd_free_work_struct(work);
|
||||
return -EINVAL;
|
||||
}
|
||||
ksmbd_init_smb_server(work);
|
||||
|
||||
ksmbd_conn_enqueue_request(work);
|
||||
atomic_inc(&conn->r_count);
|
||||
|
@ -229,9 +229,6 @@ int init_smb2_neg_rsp(struct ksmbd_work *work)
|
||||
struct smb2_negotiate_rsp *rsp;
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
|
||||
if (conn->need_neg == false)
|
||||
return -EINVAL;
|
||||
|
||||
*(__be32 *)work->response_buf =
|
||||
cpu_to_be32(conn->vals->header_size);
|
||||
|
||||
@ -498,12 +495,6 @@ int init_smb2_rsp_hdr(struct ksmbd_work *work)
|
||||
rsp_hdr->SessionId = rcv_hdr->SessionId;
|
||||
memcpy(rsp_hdr->Signature, rcv_hdr->Signature, 16);
|
||||
|
||||
work->synchronous = true;
|
||||
if (work->async_id) {
|
||||
ksmbd_release_id(&conn->async_ida, work->async_id);
|
||||
work->async_id = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -644,7 +635,7 @@ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)
|
||||
pr_err("Failed to alloc async message id\n");
|
||||
return id;
|
||||
}
|
||||
work->synchronous = false;
|
||||
work->asynchronous = true;
|
||||
work->async_id = id;
|
||||
rsp_hdr->Id.AsyncId = cpu_to_le64(id);
|
||||
|
||||
@ -664,6 +655,24 @@ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void release_async_work(struct ksmbd_work *work)
|
||||
{
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
|
||||
spin_lock(&conn->request_lock);
|
||||
list_del_init(&work->async_request_entry);
|
||||
spin_unlock(&conn->request_lock);
|
||||
|
||||
work->asynchronous = 0;
|
||||
work->cancel_fn = NULL;
|
||||
kfree(work->cancel_argv);
|
||||
work->cancel_argv = NULL;
|
||||
if (work->async_id) {
|
||||
ksmbd_release_id(&conn->async_ida, work->async_id);
|
||||
work->async_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status)
|
||||
{
|
||||
struct smb2_hdr *rsp_hdr;
|
||||
@ -7045,13 +7054,9 @@ skip:
|
||||
|
||||
ksmbd_vfs_posix_lock_wait(flock);
|
||||
|
||||
spin_lock(&work->conn->request_lock);
|
||||
spin_lock(&fp->f_lock);
|
||||
list_del(&work->fp_entry);
|
||||
work->cancel_fn = NULL;
|
||||
kfree(argv);
|
||||
spin_unlock(&fp->f_lock);
|
||||
spin_unlock(&work->conn->request_lock);
|
||||
|
||||
if (work->state != KSMBD_WORK_ACTIVE) {
|
||||
list_del(&smb_lock->llist);
|
||||
@ -7069,6 +7074,7 @@ skip:
|
||||
work->send_no_response = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
init_smb2_rsp_hdr(work);
|
||||
smb2_set_err_rsp(work);
|
||||
rsp->hdr.Status =
|
||||
@ -7081,7 +7087,7 @@ skip:
|
||||
spin_lock(&work->conn->llist_lock);
|
||||
list_del(&smb_lock->clist);
|
||||
spin_unlock(&work->conn->llist_lock);
|
||||
|
||||
release_async_work(work);
|
||||
goto retry;
|
||||
} else if (!rc) {
|
||||
spin_lock(&work->conn->llist_lock);
|
||||
|
@ -486,6 +486,7 @@ int find_matching_smb2_dialect(int start_index, __le16 *cli_dialects,
|
||||
struct file_lock *smb_flock_init(struct file *f);
|
||||
int setup_async_work(struct ksmbd_work *work, void (*fn)(void **),
|
||||
void **arg);
|
||||
void release_async_work(struct ksmbd_work *work);
|
||||
void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status);
|
||||
struct channel *lookup_chann_list(struct ksmbd_session *sess,
|
||||
struct ksmbd_conn *conn);
|
||||
|
@ -283,20 +283,121 @@ err_out:
|
||||
return BAD_PROT_ID;
|
||||
}
|
||||
|
||||
int ksmbd_init_smb_server(struct ksmbd_work *work)
|
||||
{
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
#define SMB_COM_NEGOTIATE_EX 0x0
|
||||
|
||||
if (conn->need_neg == false)
|
||||
/**
|
||||
* get_smb1_cmd_val() - get smb command value from smb header
|
||||
* @work: smb work containing smb header
|
||||
*
|
||||
* Return: smb command value
|
||||
*/
|
||||
static u16 get_smb1_cmd_val(struct ksmbd_work *work)
|
||||
{
|
||||
return SMB_COM_NEGOTIATE_EX;
|
||||
}
|
||||
|
||||
/**
|
||||
* init_smb1_rsp_hdr() - initialize smb negotiate response header
|
||||
* @work: smb work containing smb request
|
||||
*
|
||||
* Return: 0 on success, otherwise -EINVAL
|
||||
*/
|
||||
static int init_smb1_rsp_hdr(struct ksmbd_work *work)
|
||||
{
|
||||
struct smb_hdr *rsp_hdr = (struct smb_hdr *)work->response_buf;
|
||||
struct smb_hdr *rcv_hdr = (struct smb_hdr *)work->request_buf;
|
||||
|
||||
/*
|
||||
* Remove 4 byte direct TCP header.
|
||||
*/
|
||||
*(__be32 *)work->response_buf =
|
||||
cpu_to_be32(sizeof(struct smb_hdr) - 4);
|
||||
|
||||
rsp_hdr->Command = SMB_COM_NEGOTIATE;
|
||||
*(__le32 *)rsp_hdr->Protocol = SMB1_PROTO_NUMBER;
|
||||
rsp_hdr->Flags = SMBFLG_RESPONSE;
|
||||
rsp_hdr->Flags2 = SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS |
|
||||
SMBFLG2_EXT_SEC | SMBFLG2_IS_LONG_NAME;
|
||||
rsp_hdr->Pid = rcv_hdr->Pid;
|
||||
rsp_hdr->Mid = rcv_hdr->Mid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* smb1_check_user_session() - check for valid session for a user
|
||||
* @work: smb work containing smb request buffer
|
||||
*
|
||||
* Return: 0 on success, otherwise error
|
||||
*/
|
||||
static int smb1_check_user_session(struct ksmbd_work *work)
|
||||
{
|
||||
unsigned int cmd = work->conn->ops->get_cmd_val(work);
|
||||
|
||||
if (cmd == SMB_COM_NEGOTIATE_EX)
|
||||
return 0;
|
||||
|
||||
init_smb3_11_server(conn);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* smb1_allocate_rsp_buf() - allocate response buffer for a command
|
||||
* @work: smb work containing smb request
|
||||
*
|
||||
* Return: 0 on success, otherwise -ENOMEM
|
||||
*/
|
||||
static int smb1_allocate_rsp_buf(struct ksmbd_work *work)
|
||||
{
|
||||
work->response_buf = kmalloc(MAX_CIFS_SMALL_BUFFER_SIZE,
|
||||
GFP_KERNEL | __GFP_ZERO);
|
||||
work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
|
||||
|
||||
if (!work->response_buf) {
|
||||
pr_err("Failed to allocate %u bytes buffer\n",
|
||||
MAX_CIFS_SMALL_BUFFER_SIZE);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (conn->ops->get_cmd_val(work) != SMB_COM_NEGOTIATE)
|
||||
conn->need_neg = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct smb_version_ops smb1_server_ops = {
|
||||
.get_cmd_val = get_smb1_cmd_val,
|
||||
.init_rsp_hdr = init_smb1_rsp_hdr,
|
||||
.allocate_rsp_buf = smb1_allocate_rsp_buf,
|
||||
.check_user_session = smb1_check_user_session,
|
||||
};
|
||||
|
||||
static int smb1_negotiate(struct ksmbd_work *work)
|
||||
{
|
||||
return ksmbd_smb_negotiate_common(work, SMB_COM_NEGOTIATE);
|
||||
}
|
||||
|
||||
static struct smb_version_cmds smb1_server_cmds[1] = {
|
||||
[SMB_COM_NEGOTIATE_EX] = { .proc = smb1_negotiate, },
|
||||
};
|
||||
|
||||
static void init_smb1_server(struct ksmbd_conn *conn)
|
||||
{
|
||||
conn->ops = &smb1_server_ops;
|
||||
conn->cmds = smb1_server_cmds;
|
||||
conn->max_cmds = ARRAY_SIZE(smb1_server_cmds);
|
||||
}
|
||||
|
||||
void ksmbd_init_smb_server(struct ksmbd_work *work)
|
||||
{
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
__le32 proto;
|
||||
|
||||
if (conn->need_neg == false)
|
||||
return;
|
||||
|
||||
proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol;
|
||||
if (proto == SMB1_PROTO_NUMBER)
|
||||
init_smb1_server(conn);
|
||||
else
|
||||
init_smb3_11_server(conn);
|
||||
}
|
||||
|
||||
int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level,
|
||||
struct ksmbd_file *dir,
|
||||
struct ksmbd_dir_info *d_info,
|
||||
@ -444,20 +545,10 @@ static int smb_handle_negotiate(struct ksmbd_work *work)
|
||||
|
||||
ksmbd_debug(SMB, "Unsupported SMB1 protocol\n");
|
||||
|
||||
/*
|
||||
* 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);
|
||||
/* Add 2 byte bcc and 2 byte DialectIndex. */
|
||||
inc_rfc1001_len(work->response_buf, 4);
|
||||
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;
|
||||
@ -473,24 +564,13 @@ int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command)
|
||||
ksmbd_negotiate_smb_dialect(work->request_buf);
|
||||
ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
|
||||
|
||||
if (command == SMB2_NEGOTIATE_HE) {
|
||||
struct smb2_hdr *smb2_hdr = smb2_get_msg(work->request_buf);
|
||||
|
||||
if (smb2_hdr->ProtocolId != SMB2_PROTO_NUMBER) {
|
||||
ksmbd_debug(SMB, "Downgrade to SMB1 negotiation\n");
|
||||
command = SMB_COM_NEGOTIATE;
|
||||
}
|
||||
}
|
||||
|
||||
if (command == SMB2_NEGOTIATE_HE) {
|
||||
ret = smb2_handle_negotiate(work);
|
||||
init_smb2_neg_rsp(work);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (command == SMB_COM_NEGOTIATE) {
|
||||
if (__smb2_negotiate(conn)) {
|
||||
conn->need_neg = true;
|
||||
init_smb3_11_server(conn);
|
||||
init_smb2_neg_rsp(work);
|
||||
ksmbd_debug(SMB, "Upgrade to SMB2 negotiation\n");
|
||||
|
@ -427,7 +427,7 @@ bool ksmbd_smb_request(struct ksmbd_conn *conn);
|
||||
|
||||
int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count);
|
||||
|
||||
int ksmbd_init_smb_server(struct ksmbd_work *work);
|
||||
void ksmbd_init_smb_server(struct ksmbd_work *work);
|
||||
|
||||
struct ksmbd_kstat;
|
||||
int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work,
|
||||
|
@ -113,24 +113,6 @@ cp_convert:
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* is_char_allowed() - check for valid character
|
||||
* @ch: input character to be checked
|
||||
*
|
||||
* Return: 1 if char is allowed, otherwise 0
|
||||
*/
|
||||
static inline int is_char_allowed(char *ch)
|
||||
{
|
||||
/* check for control chars, wildcards etc. */
|
||||
if (!(*ch & 0x80) &&
|
||||
(*ch <= 0x1f ||
|
||||
*ch == '?' || *ch == '"' || *ch == '<' ||
|
||||
*ch == '>' || *ch == '|'))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* smb_from_utf16() - convert utf16le string to local charset
|
||||
* @to: destination buffer
|
||||
|
Loading…
x
Reference in New Issue
Block a user