Commit 7c0ec89d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '5.13-rc4-smb3' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:
 "Three SMB3 fixes.

  Two for stable, and the other fixes a problem pointed out with a
  recently added ioctl"

* tag '5.13-rc4-smb3' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: change format of CIFS_FULL_KEY_DUMP ioctl
  cifs: fix string declarations and assignments in tracepoints
  cifs: set server->cipher_type to AES-128-CCM for SMB3.0
parents 5ff2756a 1bb56810
Loading
Loading
Loading
Loading
+19 −6
Original line number Diff line number Diff line
@@ -72,15 +72,28 @@ struct smb3_key_debug_info {
} __packed;

/*
 * Dump full key (32 byte encrypt/decrypt keys instead of 16 bytes)
 * is needed if GCM256 (stronger encryption) negotiated
 * Dump variable-sized keys
 */
struct smb3_full_key_debug_info {
	__u64	Suid;
	/* INPUT: size of userspace buffer */
	__u32   in_size;

	/*
	 * INPUT: 0 for current user, otherwise session to dump
	 * OUTPUT: session id that was dumped
	 */
	__u64	session_id;
	__u16	cipher_type;
	__u8	auth_key[16]; /* SMB2_NTLMV2_SESSKEY_SIZE */
	__u8	smb3encryptionkey[32]; /* SMB3_ENC_DEC_KEY_SIZE */
	__u8	smb3decryptionkey[32]; /* SMB3_ENC_DEC_KEY_SIZE */
	__u8    session_key_length;
	__u8    server_in_key_length;
	__u8    server_out_key_length;
	__u8    data[];
	/*
	 * return this struct with the keys appended at the end:
	 * __u8 session_key[session_key_length];
	 * __u8 server_in_key[server_in_key_length];
	 * __u8 server_out_key[server_out_key_length];
	 */
} __packed;

struct smb3_notify {
+2 −1
Original line number Diff line number Diff line
@@ -148,7 +148,8 @@
#define SMB3_SIGN_KEY_SIZE (16)

/*
 * Size of the smb3 encryption/decryption keys
 * Size of the smb3 encryption/decryption key storage.
 * This size is big enough to store any cipher key types.
 */
#define SMB3_ENC_DEC_KEY_SIZE (32)

+105 −38
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include "cifsfs.h"
#include "cifs_ioctl.h"
#include "smb2proto.h"
#include "smb2glob.h"
#include <linux/btrfs.h>

static long cifs_ioctl_query_info(unsigned int xid, struct file *filep,
@@ -214,48 +215,112 @@ static int cifs_shutdown(struct super_block *sb, unsigned long arg)
	return 0;
}

static int cifs_dump_full_key(struct cifs_tcon *tcon, unsigned long arg)
static int cifs_dump_full_key(struct cifs_tcon *tcon, struct smb3_full_key_debug_info __user *in)
{
	struct smb3_full_key_debug_info pfull_key_inf;
	__u64 suid;
	struct list_head *tmp;
	struct smb3_full_key_debug_info out;
	struct cifs_ses *ses;
	int rc = 0;
	bool found = false;
	u8 __user *end;

	if (!smb3_encryption_required(tcon)) {
		rc = -EOPNOTSUPP;
		goto out;
	}

	/* copy user input into our output buffer */
	if (copy_from_user(&out, in, sizeof(out))) {
		rc = -EINVAL;
		goto out;
	}

	if (!smb3_encryption_required(tcon))
		return -EOPNOTSUPP;
	if (!out.session_id) {
		/* if ses id is 0, use current user session */
		ses = tcon->ses;
	} else {
		/* otherwise if a session id is given, look for it in all our sessions */
		struct cifs_ses *ses_it = NULL;
		struct TCP_Server_Info *server_it = NULL;

	ses = tcon->ses; /* default to user id for current user */
	if (get_user(suid, (__u64 __user *)arg))
		suid = 0;
	if (suid) {
		/* search to see if there is a session with a matching SMB UID */
		spin_lock(&cifs_tcp_ses_lock);
		list_for_each(tmp, &tcon->ses->server->smb_ses_list) {
			ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
			if (ses->Suid == suid) {
		list_for_each_entry(server_it, &cifs_tcp_ses_list, tcp_ses_list) {
			list_for_each_entry(ses_it, &server_it->smb_ses_list, smb_ses_list) {
				if (ses_it->Suid == out.session_id) {
					ses = ses_it;
					/*
					 * since we are using the session outside the crit
					 * section, we need to make sure it won't be released
					 * so increment its refcount
					 */
					ses->ses_count++;
					found = true;
				break;
					goto search_end;
				}
			}
		}
search_end:
		spin_unlock(&cifs_tcp_ses_lock);
		if (found == false)
			return -EINVAL;
	} /* else uses default user's SMB UID (ie current user) */
		if (!found) {
			rc = -ENOENT;
			goto out;
		}
	}

	pfull_key_inf.cipher_type = le16_to_cpu(ses->server->cipher_type);
	pfull_key_inf.Suid = ses->Suid;
	memcpy(pfull_key_inf.auth_key, ses->auth_key.response,
	       16 /* SMB2_NTLMV2_SESSKEY_SIZE */);
	memcpy(pfull_key_inf.smb3decryptionkey, ses->smb3decryptionkey,
	       32 /* SMB3_ENC_DEC_KEY_SIZE */);
	memcpy(pfull_key_inf.smb3encryptionkey,
	       ses->smb3encryptionkey, 32 /* SMB3_ENC_DEC_KEY_SIZE */);
	if (copy_to_user((void __user *)arg, &pfull_key_inf,
			 sizeof(struct smb3_full_key_debug_info)))
		return -EFAULT;
	switch (ses->server->cipher_type) {
	case SMB2_ENCRYPTION_AES128_CCM:
	case SMB2_ENCRYPTION_AES128_GCM:
		out.session_key_length = CIFS_SESS_KEY_SIZE;
		out.server_in_key_length = out.server_out_key_length = SMB3_GCM128_CRYPTKEY_SIZE;
		break;
	case SMB2_ENCRYPTION_AES256_CCM:
	case SMB2_ENCRYPTION_AES256_GCM:
		out.session_key_length = CIFS_SESS_KEY_SIZE;
		out.server_in_key_length = out.server_out_key_length = SMB3_GCM256_CRYPTKEY_SIZE;
		break;
	default:
		rc = -EOPNOTSUPP;
		goto out;
	}

	return 0;
	/* check if user buffer is big enough to store all the keys */
	if (out.in_size < sizeof(out) + out.session_key_length + out.server_in_key_length
	    + out.server_out_key_length) {
		rc = -ENOBUFS;
		goto out;
	}

	out.session_id = ses->Suid;
	out.cipher_type = le16_to_cpu(ses->server->cipher_type);

	/* overwrite user input with our output */
	if (copy_to_user(in, &out, sizeof(out))) {
		rc = -EINVAL;
		goto out;
	}

	/* append all the keys at the end of the user buffer */
	end = in->data;
	if (copy_to_user(end, ses->auth_key.response, out.session_key_length)) {
		rc = -EINVAL;
		goto out;
	}
	end += out.session_key_length;

	if (copy_to_user(end, ses->smb3encryptionkey, out.server_in_key_length)) {
		rc = -EINVAL;
		goto out;
	}
	end += out.server_in_key_length;

	if (copy_to_user(end, ses->smb3decryptionkey, out.server_out_key_length)) {
		rc = -EINVAL;
		goto out;
	}

out:
	if (found)
		cifs_put_smb_ses(ses);
	return rc;
}

long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
@@ -371,6 +436,10 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
				rc = -EOPNOTSUPP;
			break;
		case CIFS_DUMP_KEY:
			/*
			 * Dump encryption keys. This is an old ioctl that only
			 * handles AES-128-{CCM,GCM}.
			 */
			if (pSMBFile == NULL)
				break;
			if (!capable(CAP_SYS_ADMIN)) {
@@ -398,11 +467,10 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
			else
				rc = 0;
			break;
		case CIFS_DUMP_FULL_KEY:
			/*
		 * Dump full key (32 bytes instead of 16 bytes) is
		 * needed if GCM256 (stronger encryption) negotiated
			 * Dump encryption keys (handles any key sizes)
			 */
		case CIFS_DUMP_FULL_KEY:
			if (pSMBFile == NULL)
				break;
			if (!capable(CAP_SYS_ADMIN)) {
@@ -410,8 +478,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
				break;
			}
			tcon = tlink_tcon(pSMBFile->tlink);
			rc = cifs_dump_full_key(tcon, arg);

			rc = cifs_dump_full_key(tcon, (void __user *)arg);
			break;
		case CIFS_IOC_NOTIFY:
			if (!S_ISDIR(inode->i_mode)) {
+7 −0
Original line number Diff line number Diff line
@@ -958,6 +958,13 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
	/* Internal types */
	server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES;

	/*
	 * SMB3.0 supports only 1 cipher and doesn't have a encryption neg context
	 * Set the cipher type manually.
	 */
	if (server->dialect == SMB30_PROT_ID && (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
		server->cipher_type = SMB2_ENCRYPTION_AES128_CCM;

	security_blob = smb2_get_data_area_len(&blob_offset, &blob_length,
					       (struct smb2_sync_hdr *)rsp);
	/*
+17 −12
Original line number Diff line number Diff line
@@ -12,6 +12,11 @@

#include <linux/tracepoint.h>

/*
 * Please use this 3-part article as a reference for writing new tracepoints:
 * https://lwn.net/Articles/379903/
 */

/* For logging errors in read or write */
DECLARE_EVENT_CLASS(smb3_rw_err_class,
	TP_PROTO(unsigned int xid,
@@ -529,16 +534,16 @@ DECLARE_EVENT_CLASS(smb3_exit_err_class,
	TP_ARGS(xid, func_name, rc),
	TP_STRUCT__entry(
		__field(unsigned int, xid)
		__field(const char *, func_name)
		__string(func_name, func_name)
		__field(int, rc)
	),
	TP_fast_assign(
		__entry->xid = xid;
		__entry->func_name = func_name;
		__assign_str(func_name, func_name);
		__entry->rc = rc;
	),
	TP_printk("\t%s: xid=%u rc=%d",
		__entry->func_name, __entry->xid, __entry->rc)
		__get_str(func_name), __entry->xid, __entry->rc)
)

#define DEFINE_SMB3_EXIT_ERR_EVENT(name)          \
@@ -583,14 +588,14 @@ DECLARE_EVENT_CLASS(smb3_enter_exit_class,
	TP_ARGS(xid, func_name),
	TP_STRUCT__entry(
		__field(unsigned int, xid)
		__field(const char *, func_name)
		__string(func_name, func_name)
	),
	TP_fast_assign(
		__entry->xid = xid;
		__entry->func_name = func_name;
		__assign_str(func_name, func_name);
	),
	TP_printk("\t%s: xid=%u",
		__entry->func_name, __entry->xid)
		__get_str(func_name), __entry->xid)
)

#define DEFINE_SMB3_ENTER_EXIT_EVENT(name)        \
@@ -857,16 +862,16 @@ DECLARE_EVENT_CLASS(smb3_reconnect_class,
	TP_STRUCT__entry(
		__field(__u64, currmid)
		__field(__u64, conn_id)
		__field(char *, hostname)
		__string(hostname, hostname)
	),
	TP_fast_assign(
		__entry->currmid = currmid;
		__entry->conn_id = conn_id;
		__entry->hostname = hostname;
		__assign_str(hostname, hostname);
	),
	TP_printk("conn_id=0x%llx server=%s current_mid=%llu",
		__entry->conn_id,
		__entry->hostname,
		__get_str(hostname),
		__entry->currmid)
)

@@ -891,7 +896,7 @@ DECLARE_EVENT_CLASS(smb3_credit_class,
	TP_STRUCT__entry(
		__field(__u64, currmid)
		__field(__u64, conn_id)
		__field(char *, hostname)
		__string(hostname, hostname)
		__field(int, credits)
		__field(int, credits_to_add)
		__field(int, in_flight)
@@ -899,7 +904,7 @@ DECLARE_EVENT_CLASS(smb3_credit_class,
	TP_fast_assign(
		__entry->currmid = currmid;
		__entry->conn_id = conn_id;
		__entry->hostname = hostname;
		__assign_str(hostname, hostname);
		__entry->credits = credits;
		__entry->credits_to_add = credits_to_add;
		__entry->in_flight = in_flight;
@@ -907,7 +912,7 @@ DECLARE_EVENT_CLASS(smb3_credit_class,
	TP_printk("conn_id=0x%llx server=%s current_mid=%llu "
			"credits=%d credit_change=%d in_flight=%d",
		__entry->conn_id,
		__entry->hostname,
		__get_str(hostname),
		__entry->currmid,
		__entry->credits,
		__entry->credits_to_add,