Skip to content

Commit

Permalink
ksmbd: add support for SMB3 multichannel
Browse files Browse the repository at this point in the history
Add support for SMB3 multichannel. It will be enable by setting
'server multi channel support = yes' in smb.conf.

Signed-off-by: Namjae Jeon <[email protected]>
Signed-off-by: Steve French <[email protected]>
  • Loading branch information
namjaejeon committed Jun 18, 2021
1 parent 5fb6886 commit f5a544e
Show file tree
Hide file tree
Showing 10 changed files with 220 additions and 57 deletions.
30 changes: 21 additions & 9 deletions fs/cifsd/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -921,13 +921,14 @@ static int generate_key(struct ksmbd_session *sess, struct kvec label,
}

static int generate_smb3signingkey(struct ksmbd_session *sess,
struct ksmbd_conn *conn,
const struct derivation *signing)
{
int rc;
struct channel *chann;
char *key;

chann = lookup_chann_list(sess);
chann = lookup_chann_list(sess, conn);
if (!chann)
return 0;

Expand All @@ -953,30 +954,41 @@ static int generate_smb3signingkey(struct ksmbd_session *sess,
return 0;
}

int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess)
int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess,
struct ksmbd_conn *conn)
{
struct derivation d;

d.label.iov_base = "SMB2AESCMAC";
d.label.iov_len = 12;
d.context.iov_base = "SmbSign";
d.context.iov_len = 8;
d.binding = false;
d.binding = conn->binding;

return generate_smb3signingkey(sess, &d);
return generate_smb3signingkey(sess, conn, &d);
}

int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess)
int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess,
struct ksmbd_conn *conn)
{
struct derivation d;

d.label.iov_base = "SMBSigningKey";
d.label.iov_len = 14;
d.context.iov_base = sess->Preauth_HashValue;
if (conn->binding) {
struct preauth_session *preauth_sess;

preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id);
if (!preauth_sess)
return -ENOENT;
d.context.iov_base = preauth_sess->Preauth_HashValue;
} else {
d.context.iov_base = sess->Preauth_HashValue;
}
d.context.iov_len = 64;
d.binding = false;
d.binding = conn->binding;

return generate_smb3signingkey(sess, &d);
return generate_smb3signingkey(sess, conn, &d);
}

struct derivation_twin {
Expand Down Expand Up @@ -1148,7 +1160,7 @@ static int ksmbd_get_encryption_key(struct ksmbd_conn *conn, __u64 ses_id,
struct ksmbd_session *sess;
u8 *ses_enc_key;

sess = ksmbd_session_lookup(conn, ses_id);
sess = ksmbd_session_lookup_all(conn, ses_id);
if (!sess)
return -EINVAL;

Expand Down
6 changes: 4 additions & 2 deletions fs/cifsd/auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@ int ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
int n_vec, char *sig);
int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
int n_vec, char *sig);
int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess);
int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess);
int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess,
struct ksmbd_conn *conn);
int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess,
struct ksmbd_conn *conn);
int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess);
int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess);
int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
Expand Down
1 change: 1 addition & 0 deletions fs/cifsd/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ struct ksmbd_conn {
__le16 cipher_type;
__le16 compress_algorithm;
bool posix_ext_supported;
bool binding;
};

struct ksmbd_conn_ops {
Expand Down
1 change: 1 addition & 0 deletions fs/cifsd/ksmbd_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct ksmbd_heartbeat {
#define KSMBD_GLOBAL_FLAG_CACHE_TBUF BIT(1)
#define KSMBD_GLOBAL_FLAG_CACHE_RBUF BIT(2)
#define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION BIT(3)
#define KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL BIT(4)

struct ksmbd_startup_request {
__u32 flags;
Expand Down
49 changes: 48 additions & 1 deletion fs/cifsd/mgmt/user_session.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
}
}

bool ksmbd_session_id_match(struct ksmbd_session *sess, unsigned long long id)
static bool ksmbd_session_id_match(struct ksmbd_session *sess,
unsigned long long id)
{
return sess->id == id;
}
Expand Down Expand Up @@ -250,6 +251,52 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
return sess;
}

struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
unsigned long long id)
{
struct ksmbd_session *sess;

sess = ksmbd_session_lookup(conn, id);
if (!sess && conn->binding)
sess = ksmbd_session_lookup_slowpath(id);
return sess;
}

struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
u64 sess_id)
{
struct preauth_session *sess;

sess = kmalloc(sizeof(struct preauth_session), GFP_KERNEL);
if (!sess)
return NULL;

sess->id = sess_id;
memcpy(sess->Preauth_HashValue, conn->preauth_info->Preauth_HashValue,
PREAUTH_HASHVALUE_SIZE);
list_add(&sess->preauth_entry, &conn->preauth_sess_table);

return sess;
}

static bool ksmbd_preauth_session_id_match(struct preauth_session *sess,
unsigned long long id)
{
return sess->id == id;
}

struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn,
unsigned long long id)
{
struct preauth_session *sess = NULL;

list_for_each_entry(sess, &conn->preauth_sess_table, preauth_entry) {
if (ksmbd_preauth_session_id_match(sess, id))
return sess;
}
return NULL;
}

static int __init_smb2_session(struct ksmbd_session *sess)
{
int id = ksmbd_acquire_smb2_uid(&session_ida);
Expand Down
11 changes: 8 additions & 3 deletions fs/cifsd/mgmt/user_session.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ struct channel {

struct preauth_session {
__u8 Preauth_HashValue[PREAUTH_HASHVALUE_SIZE];
u64 sess_id;
struct list_head list_entry;
u64 id;
struct list_head preauth_entry;
};

struct ksmbd_session {
Expand Down Expand Up @@ -82,13 +82,18 @@ struct ksmbd_session *ksmbd_smb2_session_create(void);

void ksmbd_session_destroy(struct ksmbd_session *sess);

bool ksmbd_session_id_match(struct ksmbd_session *sess, unsigned long long id);
struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id);
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
unsigned long long id);
void ksmbd_session_register(struct ksmbd_conn *conn,
struct ksmbd_session *sess);
void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
unsigned long long id);
struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
u64 sess_id);
struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn,
unsigned long long id);

int ksmbd_acquire_tree_conn_id(struct ksmbd_session *sess);
void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id);
Expand Down
9 changes: 9 additions & 0 deletions fs/cifsd/smb2ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ void init_smb3_0_server(struct ksmbd_conn *conn)
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION &&
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;
}

/**
Expand All @@ -250,6 +253,9 @@ void init_smb3_02_server(struct ksmbd_conn *conn)
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION &&
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;
}

/**
Expand All @@ -271,6 +277,9 @@ int init_smb3_11_server(struct ksmbd_conn *conn)
if (conn->cipher_type)
conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;

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

INIT_LIST_HEAD(&conn->preauth_sess_table);
return 0;
}
Expand Down
Loading

0 comments on commit f5a544e

Please sign in to comment.