Commit 67ed868d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '5.17-rc-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull ksmbd server fixes from Steve French:

 - authentication fix

 - RDMA (smbdirect) fixes (including fix for a memory corruption, and
   some performance improvements)

 - multiple improvements for multichannel

 - misc fixes, including crediting (flow control) improvements

 - cleanup fixes, including some kernel doc fixes

* tag '5.17-rc-ksmbd-server-fixes' of git://git.samba.org/ksmbd: (23 commits)
  ksmbd: fix guest connection failure with nautilus
  ksmbd: uninitialized variable in create_socket()
  ksmbd: smbd: fix missing client's memory region invalidation
  ksmbd: add smb-direct shutdown
  ksmbd: smbd: change the default maximum read/write, receive size
  ksmbd: smbd: create MR pool
  ksmbd: add reserved room in ipc request/response
  ksmbd: smbd: call rdma_accept() under CM handler
  ksmbd: limits exceeding the maximum allowable outstanding requests
  ksmbd: move credit charge deduction under processing request
  ksmbd: add support for smb2 max credit parameter
  ksmbd: set 445 port to smbdirect port by default
  ksmbd: register ksmbd ib client with ib_register_client()
  ksmbd: Fix smb2_get_name() kernel-doc comment
  ksmbd: Delete an invalid argument description in smb2_populate_readdir_entry()
  ksmbd: Fix smb2_set_info_file() kernel-doc comment
  ksmbd: Fix buffer_check_err() kernel-doc comment
  ksmbd: fix multi session connection failure
  ksmbd: set both ipv4 and ipv6 in FSCTL_QUERY_NETWORK_INTERFACE_INFO
  ksmbd: set RSS capable in FSCTL_QUERY_NETWORK_INTERFACE_INFO
  ...
parents c5a0b6e4 ac090d9c
Loading
Loading
Loading
Loading
+19 −123
Original line number Diff line number Diff line
@@ -21,101 +21,11 @@
#include "ksmbd_spnego_negtokeninit.asn1.h"
#include "ksmbd_spnego_negtokentarg.asn1.h"

#define SPNEGO_OID_LEN 7
#define NTLMSSP_OID_LEN  10
#define KRB5_OID_LEN  7
#define KRB5U2U_OID_LEN  8
#define MSKRB5_OID_LEN  7
static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 };
static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 };
static unsigned long KRB5_OID[7] = { 1, 2, 840, 113554, 1, 2, 2 };
static unsigned long KRB5U2U_OID[8] = { 1, 2, 840, 113554, 1, 2, 2, 3 };
static unsigned long MSKRB5_OID[7] = { 1, 2, 840, 48018, 1, 2, 2 };

static char NTLMSSP_OID_STR[NTLMSSP_OID_LEN] = { 0x2b, 0x06, 0x01, 0x04, 0x01,
	0x82, 0x37, 0x02, 0x02, 0x0a };

static bool
asn1_subid_decode(const unsigned char **begin, const unsigned char *end,
		  unsigned long *subid)
{
	const unsigned char *ptr = *begin;
	unsigned char ch;

	*subid = 0;

	do {
		if (ptr >= end)
			return false;

		ch = *ptr++;
		*subid <<= 7;
		*subid |= ch & 0x7F;
	} while ((ch & 0x80) == 0x80);

	*begin = ptr;
	return true;
}

static bool asn1_oid_decode(const unsigned char *value, size_t vlen,
			    unsigned long **oid, size_t *oidlen)
{
	const unsigned char *iptr = value, *end = value + vlen;
	unsigned long *optr;
	unsigned long subid;

	vlen += 1;
	if (vlen < 2 || vlen > UINT_MAX / sizeof(unsigned long))
		goto fail_nullify;

	*oid = kmalloc(vlen * sizeof(unsigned long), GFP_KERNEL);
	if (!*oid)
		return false;

	optr = *oid;

	if (!asn1_subid_decode(&iptr, end, &subid))
		goto fail;

	if (subid < 40) {
		optr[0] = 0;
		optr[1] = subid;
	} else if (subid < 80) {
		optr[0] = 1;
		optr[1] = subid - 40;
	} else {
		optr[0] = 2;
		optr[1] = subid - 80;
	}

	*oidlen = 2;
	optr += 2;

	while (iptr < end) {
		if (++(*oidlen) > vlen)
			goto fail;

		if (!asn1_subid_decode(&iptr, end, optr++))
			goto fail;
	}
	return true;

fail:
	kfree(*oid);
fail_nullify:
	*oid = NULL;
	return false;
}

static bool oid_eq(unsigned long *oid1, unsigned int oid1len,
		   unsigned long *oid2, unsigned int oid2len)
{
	if (oid1len != oid2len)
		return false;

	return memcmp(oid1, oid2, oid1len) == 0;
}

int
ksmbd_decode_negTokenInit(unsigned char *security_blob, int length,
			  struct ksmbd_conn *conn)
@@ -252,26 +162,18 @@ int build_spnego_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen,
int ksmbd_gssapi_this_mech(void *context, size_t hdrlen, unsigned char tag,
			   const void *value, size_t vlen)
{
	unsigned long *oid;
	size_t oidlen;
	int err = 0;
	enum OID oid;

	if (!asn1_oid_decode(value, vlen, &oid, &oidlen)) {
		err = -EBADMSG;
		goto out;
	}

	if (!oid_eq(oid, oidlen, SPNEGO_OID, SPNEGO_OID_LEN))
		err = -EBADMSG;
	kfree(oid);
out:
	if (err) {
	oid = look_up_OID(value, vlen);
	if (oid != OID_spnego) {
		char buf[50];

		sprint_oid(value, vlen, buf, sizeof(buf));
		ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf);
		return -EBADMSG;
	}
	return err;

	return 0;
}

int ksmbd_neg_token_init_mech_type(void *context, size_t hdrlen,
@@ -279,37 +181,31 @@ int ksmbd_neg_token_init_mech_type(void *context, size_t hdrlen,
				   size_t vlen)
{
	struct ksmbd_conn *conn = context;
	unsigned long *oid;
	size_t oidlen;
	enum OID oid;
	int mech_type;
	char buf[50];

	if (!asn1_oid_decode(value, vlen, &oid, &oidlen))
		goto fail;

	if (oid_eq(oid, oidlen, NTLMSSP_OID, NTLMSSP_OID_LEN))
	oid = look_up_OID(value, vlen);
	if (oid == OID_ntlmssp) {
		mech_type = KSMBD_AUTH_NTLMSSP;
	else if (oid_eq(oid, oidlen, MSKRB5_OID, MSKRB5_OID_LEN))
	} else if (oid == OID_mskrb5) {
		mech_type = KSMBD_AUTH_MSKRB5;
	else if (oid_eq(oid, oidlen, KRB5_OID, KRB5_OID_LEN))
	} else if (oid == OID_krb5) {
		mech_type = KSMBD_AUTH_KRB5;
	else if (oid_eq(oid, oidlen, KRB5U2U_OID, KRB5U2U_OID_LEN))
	} else if (oid == OID_krb5u2u) {
		mech_type = KSMBD_AUTH_KRB5U2U;
	else
		goto fail;
	} else {
		char buf[50];

		sprint_oid(value, vlen, buf, sizeof(buf));
		ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf);
		return -EBADMSG;
	}

	conn->auth_mechs |= mech_type;
	if (conn->preferred_auth_mech == 0)
		conn->preferred_auth_mech = mech_type;

	kfree(oid);
	return 0;

fail:
	kfree(oid);
	sprint_oid(value, vlen, buf, sizeof(buf));
	ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf);
	return -EBADMSG;
}

int ksmbd_neg_token_init_mech_token(void *context, size_t hdrlen,
+14 −13
Original line number Diff line number Diff line
@@ -215,7 +215,7 @@ static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash,
 * Return:	0 on success, error number on error
 */
int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
		      int blen, char *domain_name)
		      int blen, char *domain_name, char *cryptkey)
{
	char ntlmv2_hash[CIFS_ENCPWD_SIZE];
	char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
@@ -256,7 +256,7 @@ int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
		goto out;
	}

	memcpy(construct, sess->ntlmssp.cryptkey, CIFS_CRYPTO_KEY_SIZE);
	memcpy(construct, cryptkey, CIFS_CRYPTO_KEY_SIZE);
	memcpy(construct + CIFS_CRYPTO_KEY_SIZE, &ntlmv2->blob_signature, blen);

	rc = crypto_shash_update(CRYPTO_HMACMD5(ctx), construct, len);
@@ -295,7 +295,8 @@ int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
 * Return:	0 on success, error number on error
 */
int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
				   int blob_len, struct ksmbd_session *sess)
				   int blob_len, struct ksmbd_conn *conn,
				   struct ksmbd_session *sess)
{
	char *domain_name;
	unsigned int nt_off, dn_off;
@@ -324,7 +325,7 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,

	/* TODO : use domain name that imported from configuration file */
	domain_name = smb_strndup_from_utf16((const char *)authblob + dn_off,
					     dn_len, true, sess->conn->local_nls);
					     dn_len, true, conn->local_nls);
	if (IS_ERR(domain_name))
		return PTR_ERR(domain_name);

@@ -333,7 +334,7 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
		    domain_name);
	ret = ksmbd_auth_ntlmv2(sess, (struct ntlmv2_resp *)((char *)authblob + nt_off),
				nt_len - CIFS_ENCPWD_SIZE,
				domain_name);
				domain_name, conn->ntlmssp.cryptkey);
	kfree(domain_name);
	return ret;
}
@@ -347,7 +348,7 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
 *
 */
int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob,
				  int blob_len, struct ksmbd_session *sess)
				  int blob_len, struct ksmbd_conn *conn)
{
	if (blob_len < sizeof(struct negotiate_message)) {
		ksmbd_debug(AUTH, "negotiate blob len %d too small\n",
@@ -361,7 +362,7 @@ int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob,
		return -EINVAL;
	}

	sess->ntlmssp.client_flags = le32_to_cpu(negblob->NegotiateFlags);
	conn->ntlmssp.client_flags = le32_to_cpu(negblob->NegotiateFlags);
	return 0;
}

@@ -375,14 +376,14 @@ int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob,
 */
unsigned int
ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
				   struct ksmbd_session *sess)
				   struct ksmbd_conn *conn)
{
	struct target_info *tinfo;
	wchar_t *name;
	__u8 *target_name;
	unsigned int flags, blob_off, blob_len, type, target_info_len = 0;
	int len, uni_len, conv_len;
	int cflags = sess->ntlmssp.client_flags;
	int cflags = conn->ntlmssp.client_flags;

	memcpy(chgblob->Signature, NTLMSSP_SIGNATURE, 8);
	chgblob->MessageType = NtLmChallenge;
@@ -403,7 +404,7 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
	if (cflags & NTLMSSP_REQUEST_TARGET)
		flags |= NTLMSSP_REQUEST_TARGET;

	if (sess->conn->use_spnego &&
	if (conn->use_spnego &&
	    (cflags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
		flags |= NTLMSSP_NEGOTIATE_EXTENDED_SEC;

@@ -414,7 +415,7 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
		return -ENOMEM;

	conv_len = smb_strtoUTF16((__le16 *)name, ksmbd_netbios_name(), len,
				  sess->conn->local_nls);
				  conn->local_nls);
	if (conv_len < 0 || conv_len > len) {
		kfree(name);
		return -EINVAL;
@@ -430,8 +431,8 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
	chgblob->TargetName.BufferOffset = cpu_to_le32(blob_off);

	/* Initialize random conn challenge */
	get_random_bytes(sess->ntlmssp.cryptkey, sizeof(__u64));
	memcpy(chgblob->Challenge, sess->ntlmssp.cryptkey,
	get_random_bytes(conn->ntlmssp.cryptkey, sizeof(__u64));
	memcpy(chgblob->Challenge, conn->ntlmssp.cryptkey,
	       CIFS_CRYPTO_KEY_SIZE);

	/* Add Target Information to security buffer */
+5 −5
Original line number Diff line number Diff line
@@ -38,16 +38,16 @@ struct kvec;
int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
			unsigned int nvec, int enc);
void ksmbd_copy_gss_neg_header(void *buf);
int ksmbd_auth_ntlm(struct ksmbd_session *sess, char *pw_buf);
int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
		      int blen, char *domain_name);
		      int blen, char *domain_name, char *cryptkey);
int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
				   int blob_len, struct ksmbd_session *sess);
				   int blob_len, struct ksmbd_conn *conn,
				   struct ksmbd_session *sess);
int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob,
				  int blob_len, struct ksmbd_session *sess);
				  int blob_len, struct ksmbd_conn *conn);
unsigned int
ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
				   struct ksmbd_session *sess);
				   struct ksmbd_conn *conn);
int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
			    int in_len,	char *out_blob, int *out_len);
int ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
+9 −1
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
	atomic_set(&conn->req_running, 0);
	atomic_set(&conn->r_count, 0);
	conn->total_credits = 1;
	conn->outstanding_credits = 1;

	init_waitqueue_head(&conn->req_running_q);
	INIT_LIST_HEAD(&conn->conns_list);
@@ -386,17 +387,24 @@ int ksmbd_conn_transport_init(void)
static void stop_sessions(void)
{
	struct ksmbd_conn *conn;
	struct ksmbd_transport *t;

again:
	read_lock(&conn_list_lock);
	list_for_each_entry(conn, &conn_list, conns_list) {
		struct task_struct *task;

		task = conn->transport->handler;
		t = conn->transport;
		task = t->handler;
		if (task)
			ksmbd_debug(CONN, "Stop session handler %s/%d\n",
				    task->comm, task_pid_nr(task));
		conn->status = KSMBD_SESS_EXITING;
		if (t->ops->shutdown) {
			read_unlock(&conn_list_lock);
			t->ops->shutdown(t);
			read_lock(&conn_list_lock);
		}
	}
	read_unlock(&conn_list_lock);

+4 −8
Original line number Diff line number Diff line
@@ -61,8 +61,8 @@ struct ksmbd_conn {
	atomic_t			req_running;
	/* References which are made for this Server object*/
	atomic_t			r_count;
	unsigned short			total_credits;
	unsigned short			max_credits;
	unsigned int			total_credits;
	unsigned int			outstanding_credits;
	spinlock_t			credits_lock;
	wait_queue_head_t		req_running_q;
	/* Lock to protect requests list*/
@@ -72,12 +72,7 @@ struct ksmbd_conn {
	int				connection_type;
	struct ksmbd_stats		stats;
	char				ClientGUID[SMB2_CLIENT_GUID_SIZE];
	union {
		/* pending trans request table */
		struct trans_state	*recent_trans;
		/* Used by ntlmssp */
		char			*ntlmssp_cryptkey;
	};
	struct ntlmssp_auth		ntlmssp;

	spinlock_t			llist_lock;
	struct list_head		lock_list;
@@ -122,6 +117,7 @@ struct ksmbd_conn_ops {
struct ksmbd_transport_ops {
	int (*prepare)(struct ksmbd_transport *t);
	void (*disconnect)(struct ksmbd_transport *t);
	void (*shutdown)(struct ksmbd_transport *t);
	int (*read)(struct ksmbd_transport *t, char *buf, unsigned int size);
	int (*writev)(struct ksmbd_transport *t, struct kvec *iovs, int niov,
		      int size, bool need_invalidate_rkey,
Loading