brintos

brintos / linux-shallow public Read only

0
0
Text · 13.6 KiB · ae50102 Raw
474 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *   Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org>4 *   Copyright (C) 2018 Samsung Electronics Co., Ltd.5 */6 7#include "glob.h"8#include "nterr.h"9#include "smb_common.h"10#include "../common/smb2status.h"11#include "mgmt/user_session.h"12#include "connection.h"13 14static int check_smb2_hdr(struct smb2_hdr *hdr)15{16	/*17	 * Make sure that this really is an SMB, that it is a response.18	 */19	if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)20		return 1;21	return 0;22}23 24/*25 *  The following table defines the expected "StructureSize" of SMB2 requests26 *  in order by SMB2 command.  This is similar to "wct" in SMB/CIFS requests.27 *28 *  Note that commands are defined in smb2pdu.h in le16 but the array below is29 *  indexed by command in host byte order30 */31static const __le16 smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {32	/* SMB2_NEGOTIATE */ cpu_to_le16(36),33	/* SMB2_SESSION_SETUP */ cpu_to_le16(25),34	/* SMB2_LOGOFF */ cpu_to_le16(4),35	/* SMB2_TREE_CONNECT */ cpu_to_le16(9),36	/* SMB2_TREE_DISCONNECT */ cpu_to_le16(4),37	/* SMB2_CREATE */ cpu_to_le16(57),38	/* SMB2_CLOSE */ cpu_to_le16(24),39	/* SMB2_FLUSH */ cpu_to_le16(24),40	/* SMB2_READ */ cpu_to_le16(49),41	/* SMB2_WRITE */ cpu_to_le16(49),42	/* SMB2_LOCK */ cpu_to_le16(48),43	/* SMB2_IOCTL */ cpu_to_le16(57),44	/* SMB2_CANCEL */ cpu_to_le16(4),45	/* SMB2_ECHO */ cpu_to_le16(4),46	/* SMB2_QUERY_DIRECTORY */ cpu_to_le16(33),47	/* SMB2_CHANGE_NOTIFY */ cpu_to_le16(32),48	/* SMB2_QUERY_INFO */ cpu_to_le16(41),49	/* SMB2_SET_INFO */ cpu_to_le16(33),50	/* use 44 for lease break */51	/* SMB2_OPLOCK_BREAK */ cpu_to_le16(36)52};53 54/*55 * The size of the variable area depends on the offset and length fields56 * located in different fields for various SMB2 requests. SMB2 requests57 * with no variable length info, show an offset of zero for the offset field.58 */59static const bool has_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] = {60	/* SMB2_NEGOTIATE */ true,61	/* SMB2_SESSION_SETUP */ true,62	/* SMB2_LOGOFF */ false,63	/* SMB2_TREE_CONNECT */	true,64	/* SMB2_TREE_DISCONNECT */ false,65	/* SMB2_CREATE */ true,66	/* SMB2_CLOSE */ false,67	/* SMB2_FLUSH */ false,68	/* SMB2_READ */	true,69	/* SMB2_WRITE */ true,70	/* SMB2_LOCK */	true,71	/* SMB2_IOCTL */ true,72	/* SMB2_CANCEL */ false, /* BB CHECK this not listed in documentation */73	/* SMB2_ECHO */ false,74	/* SMB2_QUERY_DIRECTORY */ true,75	/* SMB2_CHANGE_NOTIFY */ false,76	/* SMB2_QUERY_INFO */ true,77	/* SMB2_SET_INFO */ true,78	/* SMB2_OPLOCK_BREAK */ false79};80 81/*82 * Set length of the data area and the offset to arguments.83 * if they are invalid, return error.84 */85static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,86				  struct smb2_hdr *hdr)87{88	int ret = 0;89 90	*off = 0;91	*len = 0;92 93	/*94	 * Following commands have data areas so we have to get the location95	 * of the data buffer offset and data buffer length for the particular96	 * command.97	 */98	switch (hdr->Command) {99	case SMB2_SESSION_SETUP:100		*off = le16_to_cpu(((struct smb2_sess_setup_req *)hdr)->SecurityBufferOffset);101		*len = le16_to_cpu(((struct smb2_sess_setup_req *)hdr)->SecurityBufferLength);102		break;103	case SMB2_TREE_CONNECT:104		*off = max_t(unsigned short int,105			     le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset),106			     offsetof(struct smb2_tree_connect_req, Buffer));107		*len = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathLength);108		break;109	case SMB2_CREATE:110	{111		unsigned short int name_off =112			max_t(unsigned short int,113			      le16_to_cpu(((struct smb2_create_req *)hdr)->NameOffset),114			      offsetof(struct smb2_create_req, Buffer));115		unsigned short int name_len =116			le16_to_cpu(((struct smb2_create_req *)hdr)->NameLength);117 118		if (((struct smb2_create_req *)hdr)->CreateContextsLength) {119			*off = le32_to_cpu(((struct smb2_create_req *)120				hdr)->CreateContextsOffset);121			*len = le32_to_cpu(((struct smb2_create_req *)122				hdr)->CreateContextsLength);123			if (!name_len)124				break;125 126			if (name_off + name_len < (u64)*off + *len)127				break;128		}129 130		*off = name_off;131		*len = name_len;132		break;133	}134	case SMB2_QUERY_INFO:135		*off = max_t(unsigned int,136			     le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset),137			     offsetof(struct smb2_query_info_req, Buffer));138		*len = le32_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferLength);139		break;140	case SMB2_SET_INFO:141		*off = max_t(unsigned int,142			     le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset),143			     offsetof(struct smb2_set_info_req, Buffer));144		*len = le32_to_cpu(((struct smb2_set_info_req *)hdr)->BufferLength);145		break;146	case SMB2_READ:147		*off = le16_to_cpu(((struct smb2_read_req *)hdr)->ReadChannelInfoOffset);148		*len = le16_to_cpu(((struct smb2_read_req *)hdr)->ReadChannelInfoLength);149		break;150	case SMB2_WRITE:151		if (((struct smb2_write_req *)hdr)->DataOffset ||152		    ((struct smb2_write_req *)hdr)->Length) {153			*off = max_t(unsigned short int,154				     le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset),155				     offsetof(struct smb2_write_req, Buffer));156			*len = le32_to_cpu(((struct smb2_write_req *)hdr)->Length);157			break;158		}159 160		*off = le16_to_cpu(((struct smb2_write_req *)hdr)->WriteChannelInfoOffset);161		*len = le16_to_cpu(((struct smb2_write_req *)hdr)->WriteChannelInfoLength);162		break;163	case SMB2_QUERY_DIRECTORY:164		*off = max_t(unsigned short int,165			     le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset),166			     offsetof(struct smb2_query_directory_req, Buffer));167		*len = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameLength);168		break;169	case SMB2_LOCK:170	{171		unsigned short lock_count;172 173		lock_count = le16_to_cpu(((struct smb2_lock_req *)hdr)->LockCount);174		if (lock_count > 0) {175			*off = offsetof(struct smb2_lock_req, locks);176			*len = sizeof(struct smb2_lock_element) * lock_count;177		}178		break;179	}180	case SMB2_IOCTL:181		*off = max_t(unsigned int,182			     le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset),183			     offsetof(struct smb2_ioctl_req, Buffer));184		*len = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputCount);185		break;186	default:187		ksmbd_debug(SMB, "no length check for command\n");188		break;189	}190 191	if (*off > 4096) {192		ksmbd_debug(SMB, "offset %d too large\n", *off);193		ret = -EINVAL;194	} else if ((u64)*off + *len > MAX_STREAM_PROT_LEN) {195		ksmbd_debug(SMB, "Request is larger than maximum stream protocol length(%u): %llu\n",196			    MAX_STREAM_PROT_LEN, (u64)*off + *len);197		ret = -EINVAL;198	}199 200	return ret;201}202 203/*204 * Calculate the size of the SMB message based on the fixed header205 * portion, the number of word parameters and the data portion of the message.206 */207static int smb2_calc_size(void *buf, unsigned int *len)208{209	struct smb2_pdu *pdu = (struct smb2_pdu *)buf;210	struct smb2_hdr *hdr = &pdu->hdr;211	unsigned int offset; /* the offset from the beginning of SMB to data area */212	unsigned int data_length; /* the length of the variable length data area */213	int ret;214 215	/* Structure Size has already been checked to make sure it is 64 */216	*len = le16_to_cpu(hdr->StructureSize);217 218	/*219	 * StructureSize2, ie length of fixed parameter area has already220	 * been checked to make sure it is the correct length.221	 */222	*len += le16_to_cpu(pdu->StructureSize2);223	/*224	 * StructureSize2 of smb2_lock pdu is set to 48, indicating225	 * the size of smb2 lock request with single smb2_lock_element226	 * regardless of number of locks. Subtract single227	 * smb2_lock_element for correct buffer size check.228	 */229	if (hdr->Command == SMB2_LOCK)230		*len -= sizeof(struct smb2_lock_element);231 232	if (has_smb2_data_area[le16_to_cpu(hdr->Command)] == false)233		goto calc_size_exit;234 235	ret = smb2_get_data_area_len(&offset, &data_length, hdr);236	if (ret)237		return ret;238	ksmbd_debug(SMB, "SMB2 data length %u offset %u\n", data_length,239		    offset);240 241	if (data_length > 0) {242		/*243		 * Check to make sure that data area begins after fixed area,244		 * Note that last byte of the fixed area is part of data area245		 * for some commands, typically those with odd StructureSize,246		 * so we must add one to the calculation.247		 */248		if (offset + 1 < *len) {249			ksmbd_debug(SMB,250				    "data area offset %d overlaps SMB2 header %u\n",251				    offset + 1, *len);252			return -EINVAL;253		}254 255		*len = offset + data_length;256	}257 258calc_size_exit:259	ksmbd_debug(SMB, "SMB2 len %u\n", *len);260	return 0;261}262 263static inline int smb2_query_info_req_len(struct smb2_query_info_req *h)264{265	return le32_to_cpu(h->InputBufferLength) +266		le32_to_cpu(h->OutputBufferLength);267}268 269static inline int smb2_set_info_req_len(struct smb2_set_info_req *h)270{271	return le32_to_cpu(h->BufferLength);272}273 274static inline int smb2_read_req_len(struct smb2_read_req *h)275{276	return le32_to_cpu(h->Length);277}278 279static inline int smb2_write_req_len(struct smb2_write_req *h)280{281	return le32_to_cpu(h->Length);282}283 284static inline int smb2_query_dir_req_len(struct smb2_query_directory_req *h)285{286	return le32_to_cpu(h->OutputBufferLength);287}288 289static inline int smb2_ioctl_req_len(struct smb2_ioctl_req *h)290{291	return le32_to_cpu(h->InputCount) +292		le32_to_cpu(h->OutputCount);293}294 295static inline int smb2_ioctl_resp_len(struct smb2_ioctl_req *h)296{297	return le32_to_cpu(h->MaxInputResponse) +298		le32_to_cpu(h->MaxOutputResponse);299}300 301static int smb2_validate_credit_charge(struct ksmbd_conn *conn,302				       struct smb2_hdr *hdr)303{304	unsigned int req_len = 0, expect_resp_len = 0, calc_credit_num, max_len;305	unsigned short credit_charge = le16_to_cpu(hdr->CreditCharge);306	void *__hdr = hdr;307	int ret = 0;308 309	switch (hdr->Command) {310	case SMB2_QUERY_INFO:311		req_len = smb2_query_info_req_len(__hdr);312		break;313	case SMB2_SET_INFO:314		req_len = smb2_set_info_req_len(__hdr);315		break;316	case SMB2_READ:317		req_len = smb2_read_req_len(__hdr);318		break;319	case SMB2_WRITE:320		req_len = smb2_write_req_len(__hdr);321		break;322	case SMB2_QUERY_DIRECTORY:323		req_len = smb2_query_dir_req_len(__hdr);324		break;325	case SMB2_IOCTL:326		req_len = smb2_ioctl_req_len(__hdr);327		expect_resp_len = smb2_ioctl_resp_len(__hdr);328		break;329	case SMB2_CANCEL:330		return 0;331	default:332		req_len = 1;333		break;334	}335 336	credit_charge = max_t(unsigned short, credit_charge, 1);337	max_len = max_t(unsigned int, req_len, expect_resp_len);338	calc_credit_num = DIV_ROUND_UP(max_len, SMB2_MAX_BUFFER_SIZE);339 340	if (credit_charge < calc_credit_num) {341		ksmbd_debug(SMB, "Insufficient credit charge, given: %d, needed: %d\n",342			    credit_charge, calc_credit_num);343		return 1;344	} else if (credit_charge > conn->vals->max_credits) {345		ksmbd_debug(SMB, "Too large credit charge: %d\n", credit_charge);346		return 1;347	}348 349	spin_lock(&conn->credits_lock);350	if (credit_charge > conn->total_credits) {351		ksmbd_debug(SMB, "Insufficient credits granted, given: %u, granted: %u\n",352			    credit_charge, conn->total_credits);353		ret = 1;354	}355 356	if ((u64)conn->outstanding_credits + credit_charge > conn->total_credits) {357		ksmbd_debug(SMB, "Limits exceeding the maximum allowable outstanding requests, given : %u, pending : %u\n",358			    credit_charge, conn->outstanding_credits);359		ret = 1;360	} else361		conn->outstanding_credits += credit_charge;362 363	spin_unlock(&conn->credits_lock);364 365	return ret;366}367 368int ksmbd_smb2_check_message(struct ksmbd_work *work)369{370	struct smb2_pdu *pdu = ksmbd_req_buf_next(work);371	struct smb2_hdr *hdr = &pdu->hdr;372	int command;373	__u32 clc_len;  /* calculated length */374	__u32 len = get_rfc1002_len(work->request_buf);375	__u32 req_struct_size, next_cmd = le32_to_cpu(hdr->NextCommand);376 377	if ((u64)work->next_smb2_rcv_hdr_off + next_cmd > len) {378		pr_err("next command(%u) offset exceeds smb msg size\n",379				next_cmd);380		return 1;381	}382 383	if (next_cmd > 0)384		len = next_cmd;385	else if (work->next_smb2_rcv_hdr_off)386		len -= work->next_smb2_rcv_hdr_off;387 388	if (check_smb2_hdr(hdr))389		return 1;390 391	if (hdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) {392		ksmbd_debug(SMB, "Illegal structure size %u\n",393			    le16_to_cpu(hdr->StructureSize));394		return 1;395	}396 397	command = le16_to_cpu(hdr->Command);398	if (command >= NUMBER_OF_SMB2_COMMANDS) {399		ksmbd_debug(SMB, "Illegal SMB2 command %d\n", command);400		return 1;401	}402 403	if (smb2_req_struct_sizes[command] != pdu->StructureSize2) {404		if (!(command == SMB2_OPLOCK_BREAK_HE &&405		    (le16_to_cpu(pdu->StructureSize2) == OP_BREAK_STRUCT_SIZE_20 ||406		    le16_to_cpu(pdu->StructureSize2) == OP_BREAK_STRUCT_SIZE_21))) {407			/* special case for SMB2.1 lease break message */408			ksmbd_debug(SMB,409				"Illegal request size %u for command %d\n",410				le16_to_cpu(pdu->StructureSize2), command);411			return 1;412		}413	}414 415	req_struct_size = le16_to_cpu(pdu->StructureSize2) +416		__SMB2_HEADER_STRUCTURE_SIZE;417	if (command == SMB2_LOCK_HE)418		req_struct_size -= sizeof(struct smb2_lock_element);419 420	if (req_struct_size > len + 1)421		return 1;422 423	if (smb2_calc_size(hdr, &clc_len))424		return 1;425 426	if (len != clc_len) {427		/* client can return one byte more due to implied bcc[0] */428		if (clc_len == len + 1)429			goto validate_credit;430 431		/*432		 * Some windows servers (win2016) will pad also the final433		 * PDU in a compound to 8 bytes.434		 */435		if (ALIGN(clc_len, 8) == len)436			goto validate_credit;437 438		/*439		 * SMB2 NEGOTIATE request will be validated when message440		 * handling proceeds.441		 */442		if (command == SMB2_NEGOTIATE_HE)443			goto validate_credit;444 445		/*446		 * Allow a message that padded to 8byte boundary.447		 * Linux 4.19.217 with smb 3.0.2 are sometimes448		 * sending messages where the cls_len is exactly449		 * 8 bytes less than len.450		 */451		if (clc_len < len && (len - clc_len) <= 8)452			goto validate_credit;453 454		pr_err_ratelimited(455			    "cli req too short, len %d not %d. cmd:%d mid:%llu\n",456			    len, clc_len, command,457			    le64_to_cpu(hdr->MessageId));458 459		return 1;460	}461 462validate_credit:463	if ((work->conn->vals->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) &&464	    smb2_validate_credit_charge(work->conn, hdr))465		return 1;466 467	return 0;468}469 470int smb2_negotiate_request(struct ksmbd_work *work)471{472	return ksmbd_smb_negotiate_common(work, SMB2_NEGOTIATE_HE);473}474