Commit 405ac6a5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '6.9-rc2-ksmbd-server-fixes' of git://git.samba.org/ksmbd

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

   - encryption fix

   - memory overrun fix

   - oplock break fix"

* tag '6.9-rc2-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: do not set SMB2_GLOBAL_CAP_ENCRYPTION for SMB 3.1.1
  ksmbd: validate payload size in ipc response
  ksmbd: don't send oplock break if rename fails
parents fae02687 5ed11af1
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -167,7 +167,8 @@ struct ksmbd_share_config_response {
	__u16	force_uid;
	__u16	force_gid;
	__s8	share_name[KSMBD_REQ_MAX_SHARE_NAME];
	__u32	reserved[112];		/* Reserved room */
	__u32	reserved[111];		/* Reserved room */
	__u32	payload_sz;
	__u32	veto_list_sz;
	__s8	____payload[];
};
+6 −1
Original line number Diff line number Diff line
@@ -158,7 +158,12 @@ static struct ksmbd_share_config *share_config_request(struct unicode_map *um,
	share->name = kstrdup(name, GFP_KERNEL);

	if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
		share->path = kstrdup(ksmbd_share_config_path(resp),
		int path_len = PATH_MAX;

		if (resp->payload_sz)
			path_len = resp->payload_sz - resp->veto_list_sz;

		share->path = kstrndup(ksmbd_share_config_path(resp), path_len,
				      GFP_KERNEL);
		if (share->path)
			share->path_sz = strlen(share->path);
+5 −5
Original line number Diff line number Diff line
@@ -228,6 +228,11 @@ void init_smb3_0_server(struct ksmbd_conn *conn)
	    conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)
		conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;

	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION ||
	    (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) &&
	     conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION))
		conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;

	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
		conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL;
}
@@ -278,11 +283,6 @@ int init_smb3_11_server(struct ksmbd_conn *conn)
		conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING |
			SMB2_GLOBAL_CAP_DIRECTORY_LEASING;

	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION ||
	    (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) &&
	     conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION))
		conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;

	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
		conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL;

+2 −1
Original line number Diff line number Diff line
@@ -5857,8 +5857,9 @@ static int smb2_rename(struct ksmbd_work *work,
	if (!file_info->ReplaceIfExists)
		flags = RENAME_NOREPLACE;

	smb_break_all_levII_oplock(work, fp, 0);
	rc = ksmbd_vfs_rename(work, &fp->filp->f_path, new_name, flags);
	if (!rc)
		smb_break_all_levII_oplock(work, fp, 0);
out:
	kfree(new_name);
	return rc;
+37 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ struct ipc_msg_table_entry {
	struct hlist_node	ipc_table_hlist;

	void			*response;
	unsigned int		msg_sz;
};

static struct delayed_work ipc_timer_work;
@@ -275,6 +276,7 @@ static int handle_response(int type, void *payload, size_t sz)
		}

		memcpy(entry->response, payload, sz);
		entry->msg_sz = sz;
		wake_up_interruptible(&entry->wait);
		ret = 0;
		break;
@@ -453,6 +455,34 @@ static int ipc_msg_send(struct ksmbd_ipc_msg *msg)
	return ret;
}

static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
{
	unsigned int msg_sz = entry->msg_sz;

	if (entry->type == KSMBD_EVENT_RPC_REQUEST) {
		struct ksmbd_rpc_command *resp = entry->response;

		msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz;
	} else if (entry->type == KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST) {
		struct ksmbd_spnego_authen_response *resp = entry->response;

		msg_sz = sizeof(struct ksmbd_spnego_authen_response) +
				resp->session_key_len + resp->spnego_blob_len;
	} else if (entry->type == KSMBD_EVENT_SHARE_CONFIG_REQUEST) {
		struct ksmbd_share_config_response *resp = entry->response;

		if (resp->payload_sz) {
			if (resp->payload_sz < resp->veto_list_sz)
				return -EINVAL;

			msg_sz = sizeof(struct ksmbd_share_config_response) +
					resp->payload_sz;
		}
	}

	return entry->msg_sz != msg_sz ? -EINVAL : 0;
}

static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle)
{
	struct ipc_msg_table_entry entry;
@@ -477,6 +507,13 @@ static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle
	ret = wait_event_interruptible_timeout(entry.wait,
					       entry.response != NULL,
					       IPC_WAIT_TIMEOUT);
	if (entry.response) {
		ret = ipc_validate_msg(&entry);
		if (ret) {
			kvfree(entry.response);
			entry.response = NULL;
		}
	}
out:
	down_write(&ipc_msg_table_lock);
	hash_del(&entry.ipc_table_hlist);